Skip to content

Commit 3097037

Browse files
author
Max Schaefer
authored
Merge pull request #1290 from esben-semmle/js/semver-lib
JS: add SemVer library
2 parents 5b8c6d4 + fd4c749 commit 3097037

File tree

29 files changed

+374
-69
lines changed

29 files changed

+374
-69
lines changed

javascript/config/suites/javascript/security

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
+ semmlecode-javascript-queries/Security/CWE-346/CorsMisconfigurationForCredentials.ql: /Security/CWE/CWE-346
2626
+ semmlecode-javascript-queries/Security/CWE-352/MissingCsrfMiddleware.ql: /Security/CWE/CWE-352
2727
+ semmlecode-javascript-queries/Security/CWE-400/RemotePropertyInjection.ql: /Security/CWE/CWE-400
28+
+ semmlecode-javascript-queries/Security/CWE-400/PrototypePollution.ql: /Security/CWE/CWE-400
2829
+ semmlecode-javascript-queries/Security/CWE-502/UnsafeDeserialization.ql: /Security/CWE/CWE-502
2930
+ semmlecode-javascript-queries/Security/CWE-506/HardcodedDataInterpretedAsCode.ql: /Security/CWE/CWE-506
3031
+ semmlecode-javascript-queries/Security/CWE-601/ClientSideUrlRedirect.ql: /Security/CWE/CWE-601

javascript/ql/src/Security/CWE-400/PrototypePollution.ql

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,15 @@
1414
import javascript
1515
import semmle.javascript.security.dataflow.PrototypePollution::PrototypePollution
1616
import DataFlow::PathGraph
17+
import semmle.javascript.dependencies.Dependencies
1718

18-
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
19-
where cfg.hasFlowPath(source, sink)
20-
select sink.getNode(), source, sink, "Prototype pollution caused by merging a user-controlled value from $@.", source, "here"
19+
from
20+
Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, Dependency dependency,
21+
string dependencyId
22+
where
23+
cfg.hasFlowPath(source, sink) and
24+
dependency = sink.getNode().(Sink).getDependency() and
25+
dependency.info(dependencyId, _)
26+
select sink.getNode(), source, sink,
27+
"Prototype pollution caused by merging a user-controlled value from $@ using a vulnerable version of $@.",
28+
source, "here", dependency, dependencyId

javascript/ql/src/semmle/javascript/AMD.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,13 @@ private class AmdDependencyImport extends Import {
263263
not exists(super.getImportedModule()) and
264264
result = resolveByAbsolutePath()
265265
}
266+
267+
override DataFlow::Node getImportedModuleNode() {
268+
exists(Parameter param |
269+
any(AmdModuleDefinition def).dependencyParameter(this, param) and
270+
result = DataFlow::parameterNode(param)
271+
)
272+
}
266273
}
267274

268275
/**

javascript/ql/src/semmle/javascript/ES2015Modules.qll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,22 @@ class ImportDeclaration extends Stmt, Import, @importdeclaration {
4343

4444
/** Gets an import specifier of this import declaration. */
4545
ImportSpecifier getASpecifier() { result = getSpecifier(_) }
46+
47+
override DataFlow::Node getImportedModuleNode() {
48+
// `import * as http from 'http'` or `import http from `http`'
49+
exists(ImportSpecifier is |
50+
is = getASpecifier() and
51+
result = DataFlow::ssaDefinitionNode(SSA::definition(is))
52+
|
53+
is instanceof ImportNamespaceSpecifier and
54+
count(getASpecifier()) = 1
55+
or
56+
is.getImportedName() = "default"
57+
)
58+
or
59+
// `import { createServer } from 'http'`
60+
result = DataFlow::destructuredModuleImportNode(this)
61+
}
4662
}
4763

4864
/** A literal path expression appearing in an `import` declaration. */

javascript/ql/src/semmle/javascript/Expr.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,6 +1562,8 @@ class DynamicImportExpr extends @dynamicimport, Expr, Import {
15621562
override PathExpr getImportedPath() { result = getSource() }
15631563

15641564
override Module getEnclosingModule() { result = getTopLevel() }
1565+
1566+
override DataFlow::Node getImportedModuleNode() { result = DataFlow::valueNode(this) }
15651567
}
15661568

15671569
/** A literal path expression appearing in a dynamic import. */

javascript/ql/src/semmle/javascript/Modules.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ abstract class Import extends ASTNode {
160160
result = resolveFromTypeRoot()
161161
)
162162
}
163+
164+
/**
165+
* Gets the data flow node that the default import of this import is available at.
166+
*/
167+
abstract DataFlow::Node getImportedModuleNode();
163168
}
164169

165170
/**

javascript/ql/src/semmle/javascript/NodeJS.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ class Require extends CallExpr, Import {
234234
priority - (prioritiesPerCandidate() * r + numberOfExtensions() + 1))
235235
)
236236
}
237+
238+
override DataFlow::Node getImportedModuleNode() { result = DataFlow::valueNode(this) }
237239
}
238240

239241
/** An argument to `require` or `require.resolve`, considered as a path expression. */

javascript/ql/src/semmle/javascript/TypeScript.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ class ExternalModuleReference extends Expr, Import, @externalmodulereference {
212212
override ControlFlowNode getFirstControlFlowNode() {
213213
result = getExpression().getFirstControlFlowNode()
214214
}
215+
216+
override DataFlow::Node getImportedModuleNode() { result = DataFlow::valueNode(this) }
215217
}
216218

217219
/** A literal path expression appearing in an external module reference. */

javascript/ql/src/semmle/javascript/dataflow/Nodes.qll

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
import javascript
8+
import semmle.javascript.dependencies.Dependencies
89

910
/** A data flow node corresponding to an expression. */
1011
class ExprNode extends DataFlow::ValueNode {
@@ -461,37 +462,9 @@ module ModuleImportNode {
461462
string path;
462463

463464
DefaultRange() {
464-
// `require("http")`
465-
exists(Require req | req.getImportedPath().getValue() = path |
466-
this = DataFlow::valueNode(req)
467-
)
468-
or
469-
// `import http = require("http")`
470-
exists(ExternalModuleReference req | req.getImportedPath().getValue() = path |
471-
this = DataFlow::valueNode(req)
472-
)
473-
or
474-
// `import * as http from 'http'` or `import http from `http`'
475-
exists(ImportDeclaration id, ImportSpecifier is |
476-
id.getImportedPath().getValue() = path and
477-
is = id.getASpecifier() and
478-
this = DataFlow::ssaDefinitionNode(SSA::definition(is))
479-
|
480-
is instanceof ImportNamespaceSpecifier and
481-
count(id.getASpecifier()) = 1
482-
or
483-
is.getImportedName() = "default"
484-
)
485-
or
486-
// `import { createServer } from 'http'`
487-
exists(ImportDeclaration id |
488-
this = DataFlow::destructuredModuleImportNode(id) and
489-
id.getImportedPath().getValue() = path
490-
)
491-
or
492-
// declared AMD dependency
493-
exists(AmdModuleDefinition amd |
494-
this = DataFlow::parameterNode(amd.getDependencyParameter(path))
465+
exists(Import i |
466+
this = i.getImportedModuleNode() and
467+
i.getImportedPath().getValue() = path
495468
)
496469
or
497470
// AMD require
@@ -515,6 +488,15 @@ module ModuleImportNode {
515488
*/
516489
ModuleImportNode moduleImport(string path) { result.getPath() = path }
517490

491+
/**
492+
* Gets a (default) import of the given dependency `dep`, such as
493+
* `require("lodash")` in a context where a package.json file includes
494+
* `"lodash"` as a dependency.
495+
*/
496+
ModuleImportNode dependencyModuleImport(Dependency dep) {
497+
result = dep.getAUse("import").(Import).getImportedModuleNode()
498+
}
499+
518500
/**
519501
* Gets a data flow node that either imports `m` from the module with
520502
* the given `path`, or accesses `m` as a member on a default or

javascript/ql/src/semmle/javascript/dependencies/Dependencies.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ abstract class Dependency extends Locatable {
2323
/**
2424
* A use of this dependency, which is of the given `kind`.
2525
*
26-
* Currently, the only supported kind is `"import"`.
26+
* Currently, the only supported kinds are `"import"` and `"use"`.
2727
*/
2828
abstract Locatable getAUse(string kind);
2929
}

0 commit comments

Comments
 (0)