-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JS: Add support for threat models #17256
Merged
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
17a6d54
JS: Setup basic support for threat-models
RasmusWL 05dce8a
JS: Add test showing default active threat-models
RasmusWL dbfbd2c
JS: Remove 'response' from default threat-models
RasmusWL 4b1c027
JS: Integrate RemoteFlowSource with ThreatModelSource
RasmusWL f733ac1
JS: Make (most) queries use ActiveThreatModelSource
RasmusWL 412e841
JS: Add `environment` threat-model source
RasmusWL 3448751
JS: Consolidate command-line argument modeling
RasmusWL d3ae4c9
JS: Model newer `yargs` command-line parsing pattern
RasmusWL 1726287
JS: Add e2e threat-model test
RasmusWL 84f6b89
JS: Minor improvements to threat-model Concepts
RasmusWL 07bc1fe
Docs: Threat-models supported in JS
RasmusWL 7c7420a
JS: Add change-note
RasmusWL 3656864
JS: Add `database` threat-model source modeling
RasmusWL 2b6c27e
JS: Add initial `file` threat-model support
RasmusWL b47fa77
JS: Add tests for `stdin` threat-model sources
RasmusWL 971f538
JS: Include `fs` externs
RasmusWL 34b86c3
JS: Model fs.promises.readFile as file source
RasmusWL eca8bf5
JS: Do simple modeling of `process.stdin` as threat-model source
RasmusWL 61e60de
JS: Model `readline` as a `stdin` threat-model source
RasmusWL 19fae76
JS: Remove dummy comment
RasmusWL dc8e645
JS: Convert remaining queries to use ActiveThreatModelSourceAsSource
RasmusWL c0ad9ba
Merge branch 'main' into js-threat-models
RasmusWL File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
--- | ||
category: feature | ||
--- | ||
* Added support for custom threat-models, which can be used in most of our taint-tracking queries, see our [documentation](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#extending-codeql-coverage-with-threat-models) for more details. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
extensions: | ||
- addsTo: | ||
pack: codeql/threat-models | ||
extensible: threatModelConfiguration | ||
data: | ||
# Since responses are enabled by default in the shared threat-models configuration, | ||
# we need to disable it here to keep existing behavior for the javascript analysis. | ||
- ["response", false, -2147483647] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
144 changes: 144 additions & 0 deletions
144
javascript/ql/lib/semmle/javascript/frameworks/CommandLineArguments.qll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
/** Provides modeling for parsed command line arguments. */ | ||
|
||
import javascript | ||
|
||
/** | ||
* An object containing command-line arguments, potentially parsed by a library. | ||
* | ||
* Extend this class to refine existing API models. If you want to model new APIs, | ||
* extend `CommandLineArguments::Range` instead. | ||
*/ | ||
class CommandLineArguments extends ThreatModelSource instanceof CommandLineArguments::Range { } | ||
|
||
/** Provides a class for modeling new sources of remote user input. */ | ||
module CommandLineArguments { | ||
/** | ||
* An object containing command-line arguments, potentially parsed by a library. | ||
* | ||
* Extend this class to model new APIs. If you want to refine existing API models, | ||
* extend `CommandLineArguments` instead. | ||
*/ | ||
abstract class Range extends ThreatModelSource::Range { | ||
override string getThreatModel() { result = "commandargs" } | ||
|
||
override string getSourceType() { result = "CommandLineArguments" } | ||
} | ||
} | ||
|
||
/** A read of `process.argv`, considered as a threat-model source. */ | ||
private class ProcessArgv extends CommandLineArguments::Range { | ||
ProcessArgv() { | ||
// `process.argv[0]` and `process.argv[1]` are paths to `node` and `main`, and | ||
// therefore should not be considered a threat-source... However, we don't have an | ||
// easy way to exclude them, so we need to allow them. | ||
this = NodeJSLib::process().getAPropertyRead("argv") | ||
} | ||
|
||
override string getSourceType() { result = "process.argv" } | ||
} | ||
|
||
private class DefaultModels extends CommandLineArguments::Range { | ||
DefaultModels() { | ||
// `require('get-them-args')(...)` => `{ unknown: [], a: ... b: ... }` | ||
this = DataFlow::moduleImport("get-them-args").getACall() | ||
or | ||
// `require('optimist').argv` => `{ _: [], a: ... b: ... }` | ||
this = DataFlow::moduleMember("optimist", "argv") | ||
or | ||
// `require("arg")({...spec})` => `{_: [], a: ..., b: ...}` | ||
this = DataFlow::moduleImport("arg").getACall() | ||
or | ||
// `(new (require(argparse)).ArgumentParser({...spec})).parse_args()` => `{a: ..., b: ...}` | ||
this = | ||
API::moduleImport("argparse") | ||
.getMember("ArgumentParser") | ||
.getInstance() | ||
.getMember("parse_args") | ||
.getACall() | ||
or | ||
// `require('command-line-args')({...spec})` => `{a: ..., b: ...}` | ||
this = DataFlow::moduleImport("command-line-args").getACall() | ||
or | ||
// `require('meow')(help, {...spec})` => `{a: ..., b: ....}` | ||
this = DataFlow::moduleImport("meow").getACall() | ||
or | ||
// `require("dashdash").createParser(...spec)` => `{a: ..., b: ...}` | ||
this = | ||
[ | ||
API::moduleImport("dashdash"), | ||
API::moduleImport("dashdash").getMember("createParser").getReturn() | ||
].getMember("parse").getACall() | ||
or | ||
// `require('commander').myCmdArgumentName` | ||
this = commander().getAMember().asSource() | ||
or | ||
// `require('commander').opt()` => `{a: ..., b: ...}` | ||
this = commander().getMember("opts").getACall() | ||
or | ||
this = API::moduleImport("yargs/yargs").getReturn().getMember("argv").asSource() | ||
} | ||
} | ||
|
||
/** | ||
* A step for propagating taint through command line parsing, | ||
* such as `var succ = require("minimist")(pred)`. | ||
*/ | ||
private class ArgsParseStep extends TaintTracking::SharedTaintStep { | ||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) { | ||
exists(DataFlow::CallNode call | | ||
call = DataFlow::moduleMember("args", "parse").getACall() or | ||
call = DataFlow::moduleImport(["yargs-parser", "minimist", "subarg"]).getACall() | ||
| | ||
succ = call and | ||
pred = call.getArgument(0) | ||
) | ||
} | ||
} | ||
|
||
/** | ||
* Gets a Command instance from the `commander` library. | ||
*/ | ||
private API::Node commander() { | ||
result = API::moduleImport("commander") | ||
or | ||
// `require("commander").program === require("commander")` | ||
result = commander().getMember("program") | ||
or | ||
result = commander().getMember("Command").getInstance() | ||
or | ||
// lots of chainable methods | ||
result = commander().getAMember().getReturn() | ||
} | ||
|
||
/** | ||
* Gets an instance of `yargs`. | ||
* Either directly imported as a module, or through some chained method call. | ||
*/ | ||
private DataFlow::SourceNode yargs() { | ||
result = DataFlow::moduleImport("yargs") | ||
or | ||
// script used to generate list of chained methods: https://gist.github.com/erik-krogh/f8afe952c0577f4b563a993e613269ba | ||
exists(string method | | ||
not method = | ||
// the methods that does not return a chained `yargs` object. | ||
[ | ||
"getContext", "getDemandedOptions", "getDemandedCommands", "getDeprecatedOptions", | ||
"_getParseContext", "getOptions", "getGroups", "getStrict", "getStrictCommands", | ||
"getExitProcess", "locale", "getUsageInstance", "getCommandInstance" | ||
] | ||
| | ||
result = yargs().getAMethodCall(method) | ||
) | ||
} | ||
|
||
/** | ||
* An array of command line arguments (`argv`) parsed by the `yargs` library. | ||
*/ | ||
private class YargsArgv extends CommandLineArguments::Range { | ||
YargsArgv() { | ||
this = yargs().getAPropertyRead("argv") | ||
or | ||
this = yargs().getAMethodCall("parse") and | ||
this.(DataFlow::MethodCallNode).getNumArgument() = 0 | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.model.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
extensions: | ||
- addsTo: | ||
pack: codeql/javascript-all | ||
extensible: sourceModel | ||
data: | ||
- ['fs', 'Member[promises].Member[readFile].ReturnValue.Member[then].Argument[0].Parameter[0]', 'file'] | ||
- ['global', 'Member[process].Member[stdin].Member[read].ReturnValue', 'stdin'] | ||
- ['global', 'Member[process].Member[stdin].Member[on,addListener].WithStringArgument[0=data].Argument[1].Parameter[0]', 'stdin'] | ||
- ['readline', 'Member[createInterface].ReturnValue.Member[question].Argument[1].Parameter[0]', 'stdin'] | ||
- ['readline', 'Member[createInterface].ReturnValue.Member[on,addListener].WithStringArgument[0=line].Argument[1].Parameter[0]', 'stdin'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Check failure
Code scanning / CodeQL
Bidirectional imports for abstract classes Error