mirror of
https://github.com/github/codeql.git
synced 2026-04-27 09:45:15 +02:00
Merge branch 'main' into logs
This commit is contained in:
@@ -617,11 +617,11 @@ module API {
|
||||
cached
|
||||
predicate use(TApiNode nd, DataFlow::Node ref) {
|
||||
exists(string m, Module mod | nd = MkModuleDef(m) and mod = importableModule(m) |
|
||||
ref.(ModuleVarNode).getModule() = mod
|
||||
ref = DataFlow::moduleVarNode(mod)
|
||||
)
|
||||
or
|
||||
exists(string m, Module mod | nd = MkModuleExport(m) and mod = importableModule(m) |
|
||||
ref.(ExportsVarNode).getModule() = mod
|
||||
ref = DataFlow::exportsVarNode(mod)
|
||||
or
|
||||
exists(DataFlow::Node base | use(MkModuleDef(m), base) |
|
||||
ref = trackUseNode(base).getAPropertyRead("exports")
|
||||
@@ -742,12 +742,9 @@ module API {
|
||||
or
|
||||
// additional backwards step from `require('m')` to `exports` or `module.exports` in m
|
||||
exists(Import imp | imp.getImportedModuleNode() = trackDefNode(nd, t.continue()) |
|
||||
result.(ExportsVarNode).getModule() = imp.getImportedModule()
|
||||
result = DataFlow::exportsVarNode(imp.getImportedModule())
|
||||
or
|
||||
exists(ModuleVarNode mod |
|
||||
mod.getModule() = imp.getImportedModule() and
|
||||
result = mod.(DataFlow::SourceNode).getAPropertyRead("exports")
|
||||
)
|
||||
result = DataFlow::moduleVarNode(imp.getImportedModule()).getAPropertyRead("exports")
|
||||
)
|
||||
or
|
||||
t = defStep(nd, result)
|
||||
@@ -981,46 +978,3 @@ private module Label {
|
||||
/** Gets the `promisedError` edge label connecting a promise to its rejected value. */
|
||||
string promisedError() { result = "promisedError" }
|
||||
}
|
||||
|
||||
private class NodeModuleSourcesNodes extends DataFlow::SourceNode::Range {
|
||||
Variable v;
|
||||
|
||||
NodeModuleSourcesNodes() {
|
||||
exists(NodeModule m |
|
||||
this = DataFlow::ssaDefinitionNode(SSA::implicitInit(v)) and
|
||||
v = [m.getModuleVariable(), m.getExportsVariable()]
|
||||
)
|
||||
}
|
||||
|
||||
Variable getVariable() { result = v }
|
||||
}
|
||||
|
||||
/**
|
||||
* A CommonJS/AMD `module` variable.
|
||||
*/
|
||||
private class ModuleVarNode extends DataFlow::Node {
|
||||
Module m;
|
||||
|
||||
ModuleVarNode() {
|
||||
this.(NodeModuleSourcesNodes).getVariable() = m.(NodeModule).getModuleVariable()
|
||||
or
|
||||
DataFlow::parameterNode(this, m.(AmdModule).getDefine().getModuleParameter())
|
||||
}
|
||||
|
||||
Module getModule() { result = m }
|
||||
}
|
||||
|
||||
/**
|
||||
* A CommonJS/AMD `exports` variable.
|
||||
*/
|
||||
private class ExportsVarNode extends DataFlow::Node {
|
||||
Module m;
|
||||
|
||||
ExportsVarNode() {
|
||||
this.(NodeModuleSourcesNodes).getVariable() = m.(NodeModule).getExportsVariable()
|
||||
or
|
||||
DataFlow::parameterNode(this, m.(AmdModule).getDefine().getExportsParameter())
|
||||
}
|
||||
|
||||
Module getModule() { result = m }
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ module ArrayTaintTracking {
|
||||
succ = call
|
||||
or
|
||||
// `e = Array.from(x)`: if `x` is tainted, then so is `e`.
|
||||
call = DataFlow::globalVarRef("Array").getAPropertyRead("from").getACall() and
|
||||
call = arrayFromCall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
or
|
||||
@@ -79,6 +79,11 @@ module ArrayTaintTracking {
|
||||
call.(DataFlow::MethodCallNode).getMethodName() = "concat" and
|
||||
succ = call and
|
||||
pred = call.getAnArgument()
|
||||
or
|
||||
// find
|
||||
// `e = arr.find(callback)`
|
||||
call = arrayFindCall(pred) and
|
||||
succ = call
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +102,7 @@ private module ArrayDataFlow {
|
||||
DataFlow::Node pred, DataFlow::Node succ, string fromProp, string toProp
|
||||
) {
|
||||
exists(DataFlow::CallNode call |
|
||||
call = DataFlow::globalVarRef("Array").getAMemberCall("from") and
|
||||
call = arrayFromCall() and
|
||||
pred = call.getArgument(0) and
|
||||
succ = call and
|
||||
fromProp = arrayLikeElement() and
|
||||
@@ -297,4 +302,108 @@ private module ArrayDataFlow {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step modelling that elements from an array `arr` are received by calling `find`.
|
||||
*/
|
||||
private class ArrayFindStep extends DataFlow::SharedFlowStep {
|
||||
override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
exists(DataFlow::CallNode call |
|
||||
call = arrayFindCall(pred) and
|
||||
succ = call and
|
||||
prop = arrayElement()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private import ArrayLibraries
|
||||
|
||||
/**
|
||||
* Classes and predicates modelling various libraries that work on arrays or array-like structures.
|
||||
*/
|
||||
private module ArrayLibraries {
|
||||
private import DataFlow::PseudoProperties
|
||||
|
||||
/**
|
||||
* Gets a call to `Array.from` or a polyfill implementing the same functionality.
|
||||
*/
|
||||
DataFlow::CallNode arrayFromCall() {
|
||||
result = DataFlow::globalVarRef("Array").getAMemberCall("from")
|
||||
or
|
||||
result = DataFlow::moduleImport("array-from").getACall()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a call to `Array.prototype.find` or a polyfill implementing the same functionality.
|
||||
*/
|
||||
DataFlow::CallNode arrayFindCall(DataFlow::Node array) {
|
||||
result.(DataFlow::MethodCallNode).getMethodName() = "find" and
|
||||
array = result.getReceiver()
|
||||
or
|
||||
result = DataFlow::moduleImport(["array.prototype.find", "array-find"]).getACall() and
|
||||
array = result.getArgument(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint step through the `arrify` library, or other libraries that (maybe) convert values into arrays.
|
||||
*/
|
||||
private class ArrayifyStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(API::CallNode call | call = API::moduleImport(["arrify", "array-ify"]).getACall() |
|
||||
pred = call.getArgument(0) and succ = call
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to a library that copies the elements of an array into another array.
|
||||
* E.g. `array-union` that creates a union of multiple arrays, or `array-uniq` that creates an array with unique elements.
|
||||
*/
|
||||
DataFlow::CallNode arrayCopyCall(DataFlow::Node array) {
|
||||
result = API::moduleImport(["array-union", "array-uniq", "uniq"]).getACall() and
|
||||
array = result.getAnArgument()
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint step for a library that copies the elements of an array into another array.
|
||||
*/
|
||||
private class ArrayCopyTaint extends TaintTracking::SharedTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(DataFlow::CallNode call |
|
||||
call = arrayCopyCall(pred) and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A loadStoreStep for a library that copies the elements of an array into another array.
|
||||
*/
|
||||
private class ArrayCopyLoadStore extends DataFlow::SharedFlowStep {
|
||||
override predicate loadStoreStep(DataFlow::Node pred, DataFlow::Node succ, string prop) {
|
||||
exists(DataFlow::CallNode call |
|
||||
call = arrayCopyCall(pred) and
|
||||
succ = call and
|
||||
prop = arrayElement()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint step through a call to `Array.prototype.flat` or a polyfill implementing array flattening.
|
||||
*/
|
||||
private class ArrayFlatStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(DataFlow::CallNode call | succ = call |
|
||||
call.(DataFlow::MethodCallNode).getMethodName() = "flat" and
|
||||
pred = call.getReceiver()
|
||||
or
|
||||
call =
|
||||
API::moduleImport(["array-flatten", "arr-flatten", "flatten", "array.prototype.flat"])
|
||||
.getACall() and
|
||||
pred = call.getAnArgument()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,11 +178,16 @@ private class ExtendCallTaintStep extends TaintTracking::SharedTaintStep {
|
||||
private import semmle.javascript.dataflow.internal.PreCallGraphStep
|
||||
|
||||
/**
|
||||
* A step for the `clone` package.
|
||||
* A step through a cloning library, such as `clone` or `fclone`.
|
||||
*/
|
||||
private class CloneStep extends PreCallGraphStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(DataFlow::CallNode call | call = DataFlow::moduleImport("clone").getACall() |
|
||||
exists(DataFlow::CallNode call |
|
||||
// `camelcase-keys` isn't quite a cloning library. But it's pretty close.
|
||||
call = DataFlow::moduleImport(["clone", "fclone", "sort-keys", "camelcase-keys"]).getACall()
|
||||
or
|
||||
call = DataFlow::moduleMember("json-cycle", ["decycle", "retrocycle"]).getACall()
|
||||
|
|
||||
pred = call.getArgument(0) and
|
||||
succ = call
|
||||
)
|
||||
|
||||
@@ -26,6 +26,10 @@ private class PlainJsonParserCall extends JsonParserCall {
|
||||
PlainJsonParserCall() {
|
||||
exists(DataFlow::SourceNode callee | this = callee.getACall() |
|
||||
callee = DataFlow::globalVarRef("JSON").getAPropertyRead("parse") or
|
||||
callee =
|
||||
DataFlow::moduleMember(["json3", "json5", "flatted", "teleport-javascript", "json-cycle"],
|
||||
"parse") or
|
||||
callee = API::moduleImport("replicator").getInstance().getMember("decode").getAnImmediateUse() or
|
||||
callee = DataFlow::moduleImport("parse-json") or
|
||||
callee = DataFlow::moduleImport("json-parse-better-errors") or
|
||||
callee = DataFlow::moduleImport("json-safe-parse") or
|
||||
@@ -74,3 +78,15 @@ private class JsonParserCallWithCallback extends JsonParserCall {
|
||||
|
||||
override DataFlow::SourceNode getOutput() { result = getCallback(1).getParameter(1) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint step through the `strip-json-comments` library.
|
||||
*/
|
||||
private class StripJsonCommentsStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(API::CallNode call | call = API::moduleImport("strip-json-comments").getACall() |
|
||||
pred = call.getArgument(0) and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,15 @@ class JsonStringifyCall extends DataFlow::CallNode {
|
||||
JsonStringifyCall() {
|
||||
exists(DataFlow::SourceNode callee | this = callee.getACall() |
|
||||
callee = DataFlow::globalVarRef("JSON").getAPropertyRead("stringify") or
|
||||
callee = DataFlow::moduleMember("json3", "stringify") or
|
||||
callee =
|
||||
DataFlow::moduleMember(["json3", "json5", "flatted", "teleport-javascript", "json-cycle"],
|
||||
"stringify") or
|
||||
callee = API::moduleImport("replicator").getInstance().getMember("encode").getAnImmediateUse() or
|
||||
callee =
|
||||
DataFlow::moduleImport([
|
||||
"json-stringify-safe", "json-stable-stringify", "stringify-object",
|
||||
"fast-json-stable-stringify", "fast-safe-stringify", "javascript-stringify",
|
||||
"js-stringify"
|
||||
"js-stringify", "safe-stable-stringify", "fast-json-stringify"
|
||||
]) or
|
||||
// require("util").inspect() and similar
|
||||
callee = DataFlow::moduleMember("util", "inspect") or
|
||||
@@ -34,3 +37,38 @@ class JsonStringifyCall extends DataFlow::CallNode {
|
||||
*/
|
||||
DataFlow::SourceNode getOutput() { result = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint step through the [`json2csv`](https://www.npmjs.com/package/json2csv) library.
|
||||
*/
|
||||
class JSON2CSVTaintStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(API::CallNode call |
|
||||
call =
|
||||
API::moduleImport("json2csv")
|
||||
.getMember("Parser")
|
||||
.getInstance()
|
||||
.getMember("parse")
|
||||
.getACall()
|
||||
|
|
||||
pred = call.getArgument(0) and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step through the [`prettyjson`](https://www.npmjs.com/package/prettyjson) library.
|
||||
* This is not quite a `JSON.stringify` call, as it e.g. does not wrap keys in double quotes.
|
||||
* It's therefore modelled as a taint-step rather than as a `JSON.stringify` call.
|
||||
*/
|
||||
class PrettyJSONTaintStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(API::CallNode call |
|
||||
call = API::moduleImport("prettyjson").getMember("render").getACall()
|
||||
|
|
||||
pred = call.getArgument(0) and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1183,6 +1183,13 @@ private predicate flowThroughCall(
|
||||
not cfg.isLabeledBarrier(output, summary.getEndLabel())
|
||||
)
|
||||
or
|
||||
exists(Function f, LocalVariable variable |
|
||||
reachableFromInput(f, _, input, output, cfg, summary) and
|
||||
output = DataFlow::capturedVariableNode(variable) and
|
||||
getCapturedVariableDepth(variable) < getContainerDepth(f) and // Only step outwards
|
||||
not cfg.isLabeledBarrier(output, summary.getEndLabel())
|
||||
)
|
||||
or
|
||||
exists(Function f, DataFlow::Node invk, DataFlow::Node ret |
|
||||
DataFlow::exceptionalFunctionReturnNode(ret, f) and
|
||||
DataFlow::exceptionalInvocationReturnNode(output, invk.asExpr()) and
|
||||
|
||||
@@ -347,6 +347,55 @@ module SourceNode {
|
||||
}
|
||||
}
|
||||
|
||||
private class NodeModuleSourcesNodes extends SourceNode::Range {
|
||||
Variable v;
|
||||
|
||||
NodeModuleSourcesNodes() {
|
||||
exists(NodeModule m |
|
||||
this = DataFlow::ssaDefinitionNode(SSA::implicitInit(v)) and
|
||||
v = [m.getModuleVariable(), m.getExportsVariable()]
|
||||
)
|
||||
}
|
||||
|
||||
Variable getVariable() { result = v }
|
||||
}
|
||||
|
||||
/**
|
||||
* A CommonJS/AMD `module` variable.
|
||||
*/
|
||||
private class ModuleVarNode extends DataFlow::Node {
|
||||
Module m;
|
||||
|
||||
ModuleVarNode() {
|
||||
this.(NodeModuleSourcesNodes).getVariable() = m.(NodeModule).getModuleVariable()
|
||||
or
|
||||
DataFlow::parameterNode(this, m.(AmdModule).getDefine().getModuleParameter())
|
||||
}
|
||||
|
||||
Module getModule() { result = m }
|
||||
}
|
||||
|
||||
/**
|
||||
* A CommonJS/AMD `exports` variable.
|
||||
*/
|
||||
private class ExportsVarNode extends DataFlow::Node {
|
||||
Module m;
|
||||
|
||||
ExportsVarNode() {
|
||||
this.(NodeModuleSourcesNodes).getVariable() = m.(NodeModule).getExportsVariable()
|
||||
or
|
||||
DataFlow::parameterNode(this, m.(AmdModule).getDefine().getExportsParameter())
|
||||
}
|
||||
|
||||
Module getModule() { result = m }
|
||||
}
|
||||
|
||||
/** Gets the CommonJS/AMD `module` variable for module `m`. */
|
||||
SourceNode moduleVarNode(Module m) { result.(ModuleVarNode).getModule() = m }
|
||||
|
||||
/** Gets the CommonJS/AMD `exports` variable for module `m`. */
|
||||
SourceNode exportsVarNode(Module m) { result.(ExportsVarNode).getModule() = m }
|
||||
|
||||
deprecated class DefaultSourceNode extends SourceNode {
|
||||
DefaultSourceNode() { this instanceof SourceNode::DefaultRange }
|
||||
}
|
||||
|
||||
@@ -109,13 +109,30 @@ DataFlow::Node getThrowTarget(DataFlow::Node thrower) {
|
||||
*/
|
||||
cached
|
||||
private module CachedSteps {
|
||||
/** Gets the nesting depth of the given container, starting with the top-level at 0. */
|
||||
cached
|
||||
int getContainerDepth(StmtContainer container) {
|
||||
not exists(container.getEnclosingContainer()) and
|
||||
result = 0
|
||||
or
|
||||
result = 1 + getContainerDepth(container.getEnclosingContainer())
|
||||
}
|
||||
|
||||
/** Gets the nesting depth of the container declaring the given captured variable. */
|
||||
cached
|
||||
int getCapturedVariableDepth(LocalVariable v) {
|
||||
v.isCaptured() and
|
||||
result = getContainerDepth(v.getDeclaringContainer())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` captures the given `variable` in `cap`.
|
||||
*/
|
||||
cached
|
||||
predicate captures(Function f, LocalVariable variable, SsaVariableCapture cap) {
|
||||
variable = cap.getSourceVariable() and
|
||||
f = cap.getContainer()
|
||||
f = cap.getContainer() and
|
||||
not f = variable.getDeclaringContainer()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -216,20 +216,13 @@ module Angular2 {
|
||||
}
|
||||
}
|
||||
|
||||
private string getInternalName(string name) {
|
||||
exists(Identifier id |
|
||||
result = id.getName() and
|
||||
name = result.regexpCapture("\\u0275(DomAdapter|getDOM)", 1)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a reference to a `DomAdapter`, which provides acess to raw DOM elements. */
|
||||
private DataFlow::SourceNode domAdapter() {
|
||||
// Note: these are internal properties, prefixed with the "latin small letter barred O (U+0275)" character.
|
||||
// Despite being internal, some codebases do access them.
|
||||
result.hasUnderlyingType("@angular/common", getInternalName("DomAdapter"))
|
||||
result.hasUnderlyingType("@angular/common", 629.toUnicode() + "DomAdapter")
|
||||
or
|
||||
result = DataFlow::moduleImport("@angular/common").getAMemberCall(getInternalName("getDOM"))
|
||||
result = DataFlow::moduleImport("@angular/common").getAMemberCall(629.toUnicode() + "getDOM")
|
||||
}
|
||||
|
||||
/** A reference to the DOM location obtained through `DomAdapter.getLocation()`. */
|
||||
|
||||
@@ -470,3 +470,16 @@ class Chokidar extends FileNameProducer, FileSystemAccess, API::CallNode {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to the [`mkdirp`](https://www.npmjs.com/package/mkdirp) library.
|
||||
*/
|
||||
private class Mkdirp extends FileSystemAccess, API::CallNode {
|
||||
Mkdirp() {
|
||||
this = API::moduleImport("mkdirp").getACall()
|
||||
or
|
||||
this = API::moduleImport("mkdirp").getMember("sync").getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
|
||||
}
|
||||
|
||||
@@ -383,3 +383,17 @@ private module Pino {
|
||||
override DataFlow::Node getAMessageComponent() { result = getAnArgument() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step through the [`ansi-to-html`](https://npmjs.org/package/ansi-to-html) library.
|
||||
*/
|
||||
class AnsiToHtmlStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(API::CallNode call |
|
||||
call = API::moduleImport("ansi-to-html").getInstance().getMember("toHtml").getACall()
|
||||
|
|
||||
pred = call.getArgument(0) and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,3 +103,39 @@ private class LibraryFormatter extends PrintfStyleCall {
|
||||
|
||||
override predicate returnsFormatted() { returns = true }
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint step through a case changing function.
|
||||
*/
|
||||
private class CaseChangingStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate stringManipulationStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(DataFlow::SourceNode callee, DataFlow::CallNode call |
|
||||
callee = DataFlow::moduleMember("change-case", _) or
|
||||
callee = DataFlow::moduleMember("camel-case", "camelCase") or
|
||||
callee = DataFlow::moduleMember("pascal-case", "pascalCase") or
|
||||
callee = DataFlow::moduleMember("snake-case", "snakeCase") or
|
||||
callee = DataFlow::moduleImport("kebab-case") or
|
||||
callee = DataFlow::moduleMember("kebab-case", "reverse") or
|
||||
callee = DataFlow::moduleMember("param-case", "paramCase") or
|
||||
callee = DataFlow::moduleMember("path-case", "pathCase") or
|
||||
callee = DataFlow::moduleMember("sentence-case", "sentenceCase") or
|
||||
callee = DataFlow::moduleMember("title-case", "titleCase") or
|
||||
callee = DataFlow::moduleMember("upper-case", ["upperCase", "localeUpperCase"]) or
|
||||
callee = DataFlow::moduleMember("lower-case", ["lowerCase", "localeLowerCase"]) or
|
||||
callee = DataFlow::moduleMember("no-case", "noCase") or
|
||||
callee = DataFlow::moduleMember("constant-case", "constantCase") or
|
||||
callee = DataFlow::moduleMember("dot-case", "dotCase") or
|
||||
callee = DataFlow::moduleMember("upper-case-first", "upperCaseFirst") or
|
||||
callee = DataFlow::moduleMember("lower-case-first", "lowerCaseFirst") or
|
||||
callee = DataFlow::moduleMember("header-case", "headerCase") or
|
||||
callee = DataFlow::moduleMember("capital-case", "capitalCase") or
|
||||
callee = DataFlow::moduleMember("swap-case", "swapCase") or
|
||||
callee = DataFlow::moduleMember("sponge-case", "spongeCase") or
|
||||
callee = DataFlow::moduleImport(["titleize", "camelcase", "decamelize"])
|
||||
|
|
||||
call = callee.getACall() and
|
||||
pred = call.getArgument(0) and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,13 +96,8 @@ module uridashjs {
|
||||
*/
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(string name, DataFlow::CallNode call |
|
||||
name = "parse" or
|
||||
name = "serialize" or
|
||||
name = "resolve" or
|
||||
name = "normalize"
|
||||
|
|
||||
call = uridashjsMember(name).getACall() and
|
||||
exists(DataFlow::CallNode call |
|
||||
call = uridashjsMember(["parse", "serialize", "resolve", "normalize"]).getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
)
|
||||
@@ -126,13 +121,8 @@ module punycode {
|
||||
*/
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(string name, DataFlow::CallNode call |
|
||||
name = "decode" or
|
||||
name = "encode" or
|
||||
name = "toUnicode" or
|
||||
name = "toASCII"
|
||||
|
|
||||
call = punycodeMember(name).getACall() and
|
||||
exists(DataFlow::CallNode call |
|
||||
call = punycodeMember(["decode", "encode", "toUnicode", "toASCII"]).getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
)
|
||||
@@ -193,11 +183,8 @@ module querystringify {
|
||||
*/
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(string name, DataFlow::CallNode call |
|
||||
name = "parse" or
|
||||
name = "stringify"
|
||||
|
|
||||
call = querystringifyMember(name).getACall() and
|
||||
exists(DataFlow::CallNode call |
|
||||
call = querystringifyMember(["parse", "stringify"]).getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
)
|
||||
@@ -221,13 +208,8 @@ module querydashstring {
|
||||
*/
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(string name, DataFlow::CallNode call |
|
||||
name = "parse" or
|
||||
name = "extract" or
|
||||
name = "parseUrl" or
|
||||
name = "stringify"
|
||||
|
|
||||
call = querydashstringMember(name).getACall() and
|
||||
exists(DataFlow::CallNode call |
|
||||
call = querydashstringMember(["parse", "extract", "parseUrl", "stringify"]).getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
)
|
||||
@@ -249,12 +231,8 @@ module url {
|
||||
*/
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(string name, DataFlow::CallNode call |
|
||||
name = "parse" or
|
||||
name = "format" or
|
||||
name = "resolve"
|
||||
|
|
||||
call = urlMember(name).getACall() and
|
||||
exists(DataFlow::CallNode call |
|
||||
call = urlMember(["parse", "format", "resolve"]).getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
)
|
||||
@@ -278,13 +256,8 @@ module querystring {
|
||||
*/
|
||||
private class Step extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(string name, DataFlow::CallNode call |
|
||||
name = "escape" or
|
||||
name = "unescape" or
|
||||
name = "parse" or
|
||||
name = "stringify"
|
||||
|
|
||||
call = querystringMember(name).getACall() and
|
||||
exists(DataFlow::CallNode call |
|
||||
call = querystringMember(["escape", "unescape", "parse", "stringify"]).getACall() and
|
||||
pred = call.getAnArgument() and
|
||||
succ = call
|
||||
)
|
||||
@@ -292,6 +265,45 @@ module querystring {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint step through a call to [qs](https://npmjs.com/package/qs)
|
||||
*/
|
||||
private class QsStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(API::CallNode call |
|
||||
call = API::moduleImport("qs").getMember(["parse", "stringify"]).getACall()
|
||||
|
|
||||
pred = call.getArgument(0) and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint step through a call to [normalize-url](https://npmjs.com/package/normalize-url)
|
||||
*/
|
||||
private class NormalizeUrlStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(API::CallNode call | call = API::moduleImport("normalize-url").getACall() |
|
||||
pred = call.getArgument(0) and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint step through a call to [parseqs](https://npmjs.com/package/parseqs).
|
||||
*/
|
||||
private class ParseQsStep extends TaintTracking::SharedTaintStep {
|
||||
override predicate uriStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(API::CallNode call |
|
||||
call = API::moduleImport("parseqs").getMember(["encode", "decode"]).getACall() and
|
||||
pred = call.getArgument(0) and
|
||||
succ = call
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides steps for the `goog.Uri` class in the closure library.
|
||||
*/
|
||||
|
||||
@@ -169,13 +169,19 @@ module CodeInjection {
|
||||
}
|
||||
|
||||
/**
|
||||
* The first argument to `Module.prototype._compile` from the Node.js built-in module `module`,
|
||||
* considered as a code-injection sink.
|
||||
* The first argument to `Module.prototype._compile`, considered as a code-injection sink.
|
||||
*/
|
||||
class ModuleCompileSink extends Sink {
|
||||
ModuleCompileSink() {
|
||||
// `require('module').prototype._compile`
|
||||
this =
|
||||
API::moduleImport("module").getInstance().getMember("_compile").getACall().getArgument(0)
|
||||
or
|
||||
// `module.constructor.prototype._compile`
|
||||
exists(DataFlow::SourceNode moduleConstructor |
|
||||
moduleConstructor = DataFlow::moduleVarNode(_).getAPropertyRead("constructor") and
|
||||
this = moduleConstructor.getAnInstantiation().getAMethodCall("_compile").getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -682,6 +682,20 @@ module TaintedPath {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `cwd` option for the `read-pkg` library.
|
||||
*/
|
||||
private class ReadPkgCwdSink extends TaintedPath::Sink {
|
||||
ReadPkgCwdSink() {
|
||||
this =
|
||||
API::moduleImport("read-pkg")
|
||||
.getMember(["readPackageAsync", "readPackageSync"])
|
||||
.getParameter(0)
|
||||
.getMember("cwd")
|
||||
.getARhs()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a step `src -> dst` mapping `srclabel` to `dstlabel` relevant for path traversal vulnerabilities.
|
||||
*/
|
||||
@@ -798,6 +812,12 @@ module TaintedPath {
|
||||
srclabel instanceof Label::SplitPath and
|
||||
dstlabel.(Label::PosixPath).canContainDotDotSlash()
|
||||
)
|
||||
or
|
||||
exists(API::CallNode call | call = API::moduleImport("slash").getACall() |
|
||||
src = call.getArgument(0) and
|
||||
dst = call and
|
||||
srclabel = dstlabel
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -318,6 +318,20 @@ module DomBasedXss {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A React tooltip where the `data-html` attribute is set to `true`.
|
||||
*/
|
||||
class TooltipSink extends Sink {
|
||||
TooltipSink() {
|
||||
exists(JSXElement el |
|
||||
el.getAttributeByName("data-html").getStringValue() = "true" or
|
||||
el.getAttributeByName("data-html").getValue().mayHaveBooleanValue(true)
|
||||
|
|
||||
this = el.getAttributeByName("data-tip").getValue().flow()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTML body of an email, viewed as an XSS sink.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user