Merge branch 'main' into amammad-js-SQLI

This commit is contained in:
erik-krogh
2023-11-23 21:17:58 +01:00
7070 changed files with 468068 additions and 203098 deletions

View File

@@ -0,0 +1,15 @@
load("@rules_pkg//:mappings.bzl", "pkg_files")
package(default_visibility = ["//javascript:__pkg__"])
pkg_files(
name = "dbscheme",
srcs = ["semmlecode.javascript.dbscheme"],
prefix = "javascript",
)
pkg_files(
name = "dbscheme-stats",
srcs = ["semmlecode.javascript.dbscheme.stats"],
prefix = "javascript",
)

View File

@@ -1,3 +1,47 @@
## 0.8.3
No user-facing changes.
## 0.8.2
No user-facing changes.
## 0.8.1
### Minor Analysis Improvements
* The contents of `.jsp` files are now extracted, and any `<script>` tags inside these files will be parsed as JavaScript.
* [Import attributes](https://github.com/tc39/proposal-import-attributes) are now supported in JavaScript code.
Note that import attributes are an evolution of an earlier proposal called "import assertions", which were implemented in TypeScript 4.5.
The QL library includes new predicates named `getImportAttributes()` that should be used in favor of the now deprecated `getImportAssertion()`;
in addition, the `getImportAttributes()` method of the `DynamicImportExpr` has been renamed to `getImportOptions()`.
* Deleted the deprecated `getAnImmediateUse`, `getAUse`, `getARhs`, and `getAValueReachingRhs` predicates from the `API::Node` class.
* Deleted the deprecated `mayReferToParameter` predicate from `DataFlow::Node`.
* Deleted the deprecated `getStaticMethod` and `getAStaticMethod` predicates from `DataFlow::ClassNode`.
* Deleted the deprecated `isLibaryFile` predicate from `ClassifyFiles.qll`, use `isLibraryFile` instead.
* Deleted many library models that were build on the AST. Use the new models that are build on the dataflow library instead.
* Deleted the deprecated `semmle.javascript.security.performance` folder, use `semmle.javascript.security.regexp` instead.
* Tagged template literals have been added to `DataFlow::CallNode`. This allows the analysis to find flow into functions called with a tagged template literal,
and the arguments to a tagged template literal are part of the API-graph in `ApiGraphs.qll`.
## 0.8.0
No user-facing changes.
## 0.7.5
No user-facing changes.
## 0.7.4
### Major Analysis Improvements
* Added support for TypeScript 5.2.
## 0.7.3
No user-facing changes.
## 0.7.2
### Minor Analysis Improvements

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* TypeScript 5.3 is now supported.

View File

@@ -0,0 +1,3 @@
## 0.7.3
No user-facing changes.

View File

@@ -0,0 +1,5 @@
## 0.7.4
### Major Analysis Improvements
* Added support for TypeScript 5.2.

View File

@@ -0,0 +1,3 @@
## 0.7.5
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 0.8.0
No user-facing changes.

View File

@@ -0,0 +1,17 @@
## 0.8.1
### Minor Analysis Improvements
* The contents of `.jsp` files are now extracted, and any `<script>` tags inside these files will be parsed as JavaScript.
* [Import attributes](https://github.com/tc39/proposal-import-attributes) are now supported in JavaScript code.
Note that import attributes are an evolution of an earlier proposal called "import assertions", which were implemented in TypeScript 4.5.
The QL library includes new predicates named `getImportAttributes()` that should be used in favor of the now deprecated `getImportAssertion()`;
in addition, the `getImportAttributes()` method of the `DynamicImportExpr` has been renamed to `getImportOptions()`.
* Deleted the deprecated `getAnImmediateUse`, `getAUse`, `getARhs`, and `getAValueReachingRhs` predicates from the `API::Node` class.
* Deleted the deprecated `mayReferToParameter` predicate from `DataFlow::Node`.
* Deleted the deprecated `getStaticMethod` and `getAStaticMethod` predicates from `DataFlow::ClassNode`.
* Deleted the deprecated `isLibaryFile` predicate from `ClassifyFiles.qll`, use `isLibraryFile` instead.
* Deleted many library models that were build on the AST. Use the new models that are build on the dataflow library instead.
* Deleted the deprecated `semmle.javascript.security.performance` folder, use `semmle.javascript.security.regexp` instead.
* Tagged template literals have been added to `DataFlow::CallNode`. This allows the analysis to find flow into functions called with a tagged template literal,
and the arguments to a tagged template literal are part of the API-graph in `ApiGraphs.qll`.

View File

@@ -0,0 +1,3 @@
## 0.8.2
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 0.8.3
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.7.2
lastReleaseVersion: 0.8.3

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-all
version: 0.7.3-dev
version: 0.8.4-dev
groups: javascript
dbscheme: semmlecode.javascript.dbscheme
extractor: javascript

View File

@@ -7,6 +7,34 @@ import javascript
private import semmle.javascript.internal.CachedStages
private import Expressions.ExprHasNoEffect
/**
* Companion module to the `AmdModuleDefinition` class.
*/
module AmdModuleDefinition {
/**
* A class that can be extended to treat calls as instances of `AmdModuleDefinition`.
*
* Subclasses should not depend on imports or `DataFlow::Node`.
*/
abstract class Range extends CallExpr { }
private class DefaultRange extends Range {
DefaultRange() {
inVoidContext(this) and
this.getCallee().(GlobalVarAccess).getName() = "define" and
exists(int n | n = this.getNumArgument() |
n = 1
or
n = 2 and this.getArgument(0) instanceof ArrayExpr
or
n = 3 and
this.getArgument(0) instanceof ConstantString and
this.getArgument(1) instanceof ArrayExpr
)
}
}
}
/**
* An AMD `define` call.
*
@@ -25,21 +53,7 @@ private import Expressions.ExprHasNoEffect
* where the first argument is the module name, the second argument an
* array of dependencies, and the third argument a factory method or object.
*/
class AmdModuleDefinition extends CallExpr {
AmdModuleDefinition() {
inVoidContext(this) and
this.getCallee().(GlobalVarAccess).getName() = "define" and
exists(int n | n = this.getNumArgument() |
n = 1
or
n = 2 and this.getArgument(0) instanceof ArrayExpr
or
n = 3 and
this.getArgument(0) instanceof ConstantString and
this.getArgument(1) instanceof ArrayExpr
)
}
class AmdModuleDefinition extends CallExpr instanceof AmdModuleDefinition::Range {
/** Gets the array of module dependencies, if any. */
ArrayExpr getDependencies() {
result = this.getArgument(0) or

View File

@@ -153,12 +153,6 @@ module API {
*/
DataFlow::SourceNode asSource() { Impl::use(this, result) }
/** DEPRECATED. This predicate has been renamed to `asSource`. */
deprecated DataFlow::SourceNode getAnImmediateUse() { result = this.asSource() }
/** DEPRECATED. This predicate has been renamed to `getAValueReachableFromSource`. */
deprecated DataFlow::Node getAUse() { result = this.getAValueReachableFromSource() }
/**
* Gets a call to the function represented by this API component.
*/
@@ -212,12 +206,6 @@ module API {
*/
DataFlow::Node getAValueReachingSink() { result = Impl::trackDefNode(this.asSink()) }
/** DEPRECATED. This predicate has been renamed to `asSink`. */
deprecated DataFlow::Node getARhs() { result = this.asSink() }
/** DEPRECATED. This predicate has been renamed to `getAValueReachingSink`. */
deprecated DataFlow::Node getAValueReachingRhs() { result = this.getAValueReachingSink() }
/**
* Gets a node representing member `m` of this API component.
*
@@ -622,12 +610,6 @@ module API {
bindingset[this]
EntryPoint() { any() }
/** DEPRECATED. This predicate has been renamed to `getASource`. */
deprecated DataFlow::SourceNode getAUse() { none() }
/** DEPRECATED. This predicate has been renamed to `getASink`. */
deprecated DataFlow::SourceNode getARhs() { none() }
/** Gets a data-flow node where a value enters the current codebase through this entry-point. */
DataFlow::SourceNode getASource() { none() }

View File

@@ -91,14 +91,27 @@ class ImportDeclaration extends Stmt, Import, @import_declaration {
override PathExpr getImportedPath() { result = this.getChildExpr(-1) }
/**
* Gets the object literal passed as part of the `assert` clause in this import declaration.
* Gets the object literal passed as part of the `with` (or `assert`) clause in this import declaration.
*
* For example, this gets the `{ type: "json" }` object literal in the following:
* ```js
* import foo from "foo" with { type: "json" };
* import foo from "foo" assert { type: "json" };
* ```
*/
ObjectExpr getImportAssertion() { result = this.getChildExpr(-10) }
ObjectExpr getImportAttributes() { result = this.getChildExpr(-10) }
/**
* DEPRECATED: use `getImportAttributes` instead.
* Gets the object literal passed as part of the `with` (or `assert`) clause in this import declaration.
*
* For example, this gets the `{ type: "json" }` object literal in the following:
* ```js
* import foo from "foo" with { type: "json" };
* import foo from "foo" assert { type: "json" };
* ```
*/
deprecated ObjectExpr getImportAssertion() { result = this.getImportAttributes() }
/** Gets the `i`th import specifier of this import declaration. */
ImportSpecifier getSpecifier(int i) { result = this.getChildExpr(i) }
@@ -322,17 +335,33 @@ abstract class ExportDeclaration extends Stmt, @export_declaration {
override string getAPrimaryQlClass() { result = "ExportDeclaration" }
/**
* Gets the object literal passed as part of the `assert` clause, if this is
* Gets the object literal passed as part of the `with` (or `assert`) clause, if this is
* a re-export declaration.
*
* For example, this gets the `{ type: "json" }` expression in each of the following:
* ```js
* export { x } from 'foo' assert { type: "json" };
* export { x } from 'foo' with { type: "json" };
* export * from 'foo' with { type: "json" };
* export * as x from 'foo' with { type: "json" };
* export * from 'foo' assert { type: "json" };
* export * as x from 'foo' assert { type: "json" };
* ```
*/
ObjectExpr getImportAssertion() { result = this.getChildExpr(-10) }
ObjectExpr getImportAttributes() { result = this.getChildExpr(-10) }
/**
* DEPRECATED: use `getImportAttributes` instead.
* Gets the object literal passed as part of the `with` (or `assert`) clause, if this is
* a re-export declaration.
*
* For example, this gets the `{ type: "json" }` expression in each of the following:
* ```js
* export { x } from 'foo' with { type: "json" };
* export * from 'foo' with { type: "json" };
* export * as x from 'foo' with { type: "json" };
* export * from 'foo' assert { type: "json" };
* ```
*/
deprecated ObjectExpr getImportAssertion() { result = this.getImportAttributes() }
}
/**

View File

@@ -2807,7 +2807,7 @@ class FunctionBindExpr extends @bind_expr, Expr {
*
* ```
* import("fs")
* import("foo", { assert: { type: "json" }})
* import("foo", { with: { type: "json" }})
* ```
*/
class DynamicImportExpr extends @dynamic_import, Expr, Import {
@@ -2823,12 +2823,23 @@ class DynamicImportExpr extends @dynamic_import, Expr, Import {
/**
* Gets the second "argument" to the import expression, that is, the `Y` in `import(X, Y)`.
*
* For example, gets the `{ assert: { type: "json" }}` expression in the following:
* For example, gets the `{ with: { type: "json" }}` expression in the following:
* ```js
* import('foo', { assert: { type: "json" }})
* import('foo', { with: { type: "json" }})
* ```
*/
Expr getImportAttributes() { result = this.getChildExpr(1) }
Expr getImportOptions() { result = this.getChildExpr(1) }
/**
* DEPRECATED: use `getImportOptions` instead.
* Gets the second "argument" to the import expression, that is, the `Y` in `import(X, Y)`.
*
* For example, gets the `{ with: { type: "json" }}` expression in the following:
* ```js
* import('foo', { with: { type: "json" }})
* ```
*/
deprecated Expr getImportAttributes() { result = this.getImportOptions() }
override Module getEnclosingModule() { result = this.getTopLevel() }

View File

@@ -2,166 +2,34 @@
import javascript
private import NodeModuleResolutionImpl
private import codeql.util.FileSystem
/** A file or folder. */
abstract class Container extends @container {
/**
* Gets the absolute, canonical path of this container, using forward slashes
* as path separator.
*
* The path starts with a _root prefix_ followed by zero or more _path
* segments_ separated by forward slashes.
*
* The root prefix is of one of the following forms:
*
* 1. A single forward slash `/` (Unix-style)
* 2. An upper-case drive letter followed by a colon and a forward slash,
* such as `C:/` (Windows-style)
* 3. Two forward slashes, a computer name, and then another forward slash,
* such as `//FileServer/` (UNC-style)
*
* Path segments are never empty (that is, absolute paths never contain two
* contiguous slashes, except as part of a UNC-style root prefix). Also, path
* segments never contain forward slashes, and no path segment is of the
* form `.` (one dot) or `..` (two dots).
*
* Note that an absolute path never ends with a forward slash, except if it is
* a bare root prefix, that is, the path has no path segments. A container
* whose absolute path has no segments is always a `Folder`, not a `File`.
*/
abstract string getAbsolutePath();
private module FsInput implements InputSig {
abstract class ContainerBase extends @container {
abstract string getAbsolutePath();
/**
* Gets a URL representing the location of this container.
*
* For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls).
*/
abstract string getURL();
ContainerBase getParentContainer() { containerparent(result, this) }
/**
* Gets the relative path of this file or folder from the root folder of the
* analyzed source location. The relative path of the root folder itself is
* the empty string.
*
* This has no result if the container is outside the source root, that is,
* if the root folder is not a reflexive, transitive parent of this container.
*/
string getRelativePath() {
exists(string absPath, string pref |
absPath = this.getAbsolutePath() and sourceLocationPrefix(pref)
|
absPath = pref and result = ""
or
absPath = pref.regexpReplaceAll("/$", "") + "/" + result and
not result.matches("/%")
)
string toString() { result = this.getAbsolutePath() }
}
/**
* Gets the base name of this container including extension, that is, the last
* segment of its absolute path, or the empty string if it has no segments.
*
* Here are some examples of absolute paths and the corresponding base names
* (surrounded with quotes to avoid ambiguity):
*
* <table border="1">
* <tr><th>Absolute path</th><th>Base name</th></tr>
* <tr><td>"/tmp/tst.js"</td><td>"tst.js"</td></tr>
* <tr><td>"C:/Program Files (x86)"</td><td>"Program Files (x86)"</td></tr>
* <tr><td>"/"</td><td>""</td></tr>
* <tr><td>"C:/"</td><td>""</td></tr>
* <tr><td>"D:/"</td><td>""</td></tr>
* <tr><td>"//FileServer/"</td><td>""</td></tr>
* </table>
*/
string getBaseName() {
result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(\\.([^.]*))?)", 1)
class FolderBase extends ContainerBase, @folder {
override string getAbsolutePath() { folders(this, result) }
}
/**
* Gets the extension of this container, that is, the suffix of its base name
* after the last dot character, if any.
*
* In particular,
*
* - if the name does not include a dot, there is no extension, so this
* predicate has no result;
* - if the name ends in a dot, the extension is the empty string;
* - if the name contains multiple dots, the extension follows the last dot.
*
* Here are some examples of absolute paths and the corresponding extensions
* (surrounded with quotes to avoid ambiguity):
*
* <table border="1">
* <tr><th>Absolute path</th><th>Extension</th></tr>
* <tr><td>"/tmp/tst.js"</td><td>"js"</td></tr>
* <tr><td>"/tmp/.classpath"</td><td>"classpath"</td></tr>
* <tr><td>"/bin/bash"</td><td>not defined</td></tr>
* <tr><td>"/tmp/tst2."</td><td>""</td></tr>
* <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr>
* </table>
*/
string getExtension() {
result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(\\.([^.]*))?)", 4)
class FileBase extends ContainerBase, @file {
override string getAbsolutePath() { files(this, result) }
}
/**
* Gets the stem of this container, that is, the prefix of its base name up to
* (but not including) the last dot character if there is one, or the entire
* base name if there is not.
*
* Here are some examples of absolute paths and the corresponding stems
* (surrounded with quotes to avoid ambiguity):
*
* <table border="1">
* <tr><th>Absolute path</th><th>Stem</th></tr>
* <tr><td>"/tmp/tst.js"</td><td>"tst"</td></tr>
* <tr><td>"/tmp/.classpath"</td><td>""</td></tr>
* <tr><td>"/bin/bash"</td><td>"bash"</td></tr>
* <tr><td>"/tmp/tst2."</td><td>"tst2"</td></tr>
* <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr>
* </table>
*/
string getStem() {
result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(\\.([^.]*))?)", 2)
}
/** Gets the parent container of this file or folder, if any. */
Container getParentContainer() { containerparent(result, this) }
/** Gets a file or sub-folder in this container. */
Container getAChildContainer() { this = result.getParentContainer() }
/** Gets a file in this container. */
File getAFile() { result = this.getAChildContainer() }
/** Gets the file in this container that has the given `baseName`, if any. */
File getFile(string baseName) {
result = this.getAFile() and
result.getBaseName() = baseName
}
/** Gets a sub-folder in this container. */
Folder getAFolder() { result = this.getAChildContainer() }
/** Gets the sub-folder in this container that has the given `baseName`, if any. */
Folder getFolder(string baseName) {
result = this.getAFolder() and
result.getBaseName() = baseName
}
/**
* Gets a textual representation of the path of this container.
*
* This is the absolute path of the container.
*/
string toString() { result = this.getAbsolutePath() }
predicate hasSourceLocationPrefix = sourceLocationPrefix/1;
}
/** A folder. */
class Folder extends Container, @folder {
override string getAbsolutePath() { folders(this, result) }
private module Impl = Make<FsInput>;
class Container = Impl::Container;
/** A folder. */
class Folder extends Container, Impl::Folder {
/** Gets the file or subfolder in this folder that has the given `name`, if any. */
Container getChildContainer(string name) {
result = this.getAChildContainer() and
@@ -206,13 +74,10 @@ class Folder extends Container, @folder {
/** Gets a subfolder contained in this folder. */
Folder getASubFolder() { result = this.getAChildContainer() }
/** Gets the URL of this folder. */
override string getURL() { result = "folder://" + this.getAbsolutePath() }
}
/** A file. */
class File extends Container, @file {
class File extends Container, Impl::File {
/**
* Gets the location of this file.
*
@@ -220,8 +85,6 @@ class File extends Container, @file {
*/
Location getLocation() { hasLocation(this, result) }
override string getAbsolutePath() { files(this, result) }
/** Gets the number of lines in this file. */
int getNumberOfLines() { result = sum(int loc | numlines(this, loc, _, _) | loc) }
@@ -234,9 +97,6 @@ class File extends Container, @file {
/** Gets a toplevel piece of JavaScript code in this file. */
TopLevel getATopLevel() { result.getFile() = this }
/** Gets the URL of this file. */
override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
/**
* Holds if line number `lineno` of this file is indented to depth `d`
* using character `c`.

View File

@@ -246,13 +246,15 @@ private module PrintJavaScript {
}
/**
* Gets "var" or "const" or "let" depending on what type of declaration `decl` is.
* Gets "var" or "const" or "let" or "using" depending on what type of declaration `decl` is.
*/
private string getDeclarationKeyword(DeclStmt decl) {
decl instanceof VarDeclStmt and result = "var"
or
decl instanceof ConstDeclStmt and result = "const"
or
decl instanceof UsingDeclStmt and result = "using"
or
decl instanceof LetStmt and result = "let"
}
}

View File

@@ -1041,6 +1041,17 @@ class VarDeclStmt extends @var_decl_stmt, DeclStmt { }
*/
class ConstDeclStmt extends @const_decl_stmt, DeclStmt { }
/**
* A `using` declaration statement.
*
* Example:
*
* ```
* using file = new TextFile("file.txt");
* ```
*/
class UsingDeclStmt extends @using_decl_stmt, DeclStmt { }
/**
* A `let` declaration statement.
*

View File

@@ -138,14 +138,6 @@ module DataFlow {
CallGraph::getABoundFunctionReference(result, boundArgs, _).flowsTo(this)
}
/**
* DEPRECATED: Use `DataFlow::ParameterNode::flowsTo()` instead.
* Holds if this expression may refer to the initial value of parameter `p`.
*/
deprecated predicate mayReferToParameter(Parameter p) {
parameterNode(p).(SourceNode).flowsTo(this)
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
@@ -1277,6 +1269,41 @@ module DataFlow {
result >= 0 and kind = "call" and result = originalCall.getNumArgument() - 1
}
}
/**
* A data flow node representing a call with a tagged template literal.
*/
private class TaggedTemplateLiteralCallNode extends CallNodeDef, ValueNode {
override TaggedTemplateExpr astNode;
override InvokeExpr getInvokeExpr() { none() } // There is no InvokeExpr for this.
override string getCalleeName() {
result = astNode.getTag().getUnderlyingValue().(Identifier).getName()
}
override DataFlow::Node getCalleeNode() { result = DataFlow::valueNode(astNode.getTag()) }
override DataFlow::Node getArgument(int i) {
// the first argument sent to the function is the array of string parts, which we don't model.
// rank is 1-indexed, which is perfect here.
result =
DataFlow::valueNode(rank[i](Expr e, int index |
e = astNode.getTemplate().getElement(index) and not e instanceof TemplateElement
|
e order by index
))
}
override DataFlow::Node getAnArgument() { result = this.getArgument(_) }
override DataFlow::Node getASpreadArgument() { none() }
// we don't model the string constants as arguments, but we still count them.
override int getNumArgument() { result = count(this.getArgument(_)) + 1 }
override DataFlow::Node getReceiver() { none() }
}
}
/**

View File

@@ -92,13 +92,20 @@ class InvokeNode extends DataFlow::SourceNode instanceof DataFlow::Impl::InvokeN
* but the position of `z` cannot be determined, hence there are no first and second
* argument nodes.
*/
DataFlow::Node getArgument(int i) { result = super.getArgument(i) }
cached
DataFlow::Node getArgument(int i) {
result = super.getArgument(i) and Stages::DataFlowStage::ref()
}
/** Gets the data flow node corresponding to an argument of this invocation. */
DataFlow::Node getAnArgument() { result = super.getAnArgument() }
cached
DataFlow::Node getAnArgument() { result = super.getAnArgument() and Stages::DataFlowStage::ref() }
/** Gets the data flow node corresponding to the last argument of this invocation. */
DataFlow::Node getLastArgument() { result = this.getArgument(this.getNumArgument() - 1) }
cached
DataFlow::Node getLastArgument() {
result = this.getArgument(this.getNumArgument() - 1) and Stages::DataFlowStage::ref()
}
/**
* Gets a data flow node corresponding to an array of values being passed as
@@ -1150,30 +1157,12 @@ module ClassNode {
cached
abstract FunctionNode getStaticMember(string name, MemberKind kind);
/**
* DEPRECATED. Override `getStaticMember` instead.
*
* Gets the static method of this class with the given name.
*/
cached
deprecated FunctionNode getStaticMethod(string name) { none() }
/**
* Gets a static member of this class of the given kind.
*/
cached
abstract FunctionNode getAStaticMember(MemberKind kind);
/**
* DEPRECATED. Override `getAStaticMember` instead.
*
* Gets a static method of this class.
*
* The constructor is not considered a static method.
*/
cached
deprecated FunctionNode getAStaticMethod() { none() }
/**
* Gets a dataflow node representing a class to be used as the super-class
* of this node.

View File

@@ -75,9 +75,6 @@ predicate isExternsFile(File f) {
*/
predicate isLibraryFile(File f) { f.getATopLevel() instanceof FrameworkLibraryInstance }
/** DEPRECATED: Alias for isLibraryFile */
deprecated predicate isLibaryFile = isLibraryFile/1;
/**
* Holds if `f` contains template code.
*/

View File

@@ -618,27 +618,6 @@ private class JQLiteObject extends JQuery::ObjectSource::Range {
}
}
/**
* DEPRECATED: Use `AngularJSCallNode` instead.
* A call to an AngularJS function.
*
* Used for exposing behavior that is similar to the behavior of other libraries.
*/
deprecated class AngularJSCall extends CallExpr {
AngularJSCallNode node;
AngularJSCall() { this.flow() = node }
/** Holds if `e` is an argument that this call interprets as HTML. */
deprecated predicate interpretsArgumentAsHtml(Expr e) { node.interpretsArgumentAsHtml(e.flow()) }
/** Holds if `e` is an argument that this call stores globally, e.g. in a cookie. */
deprecated predicate storesArgumentGlobally(Expr e) { node.storesArgumentGlobally(e.flow()) }
/** Holds if `e` is an argument that this call interprets as code. */
deprecated predicate interpretsArgumentAsCode(Expr e) { node.interpretsArgumentAsCode(e.flow()) }
}
/**
* A call to an AngularJS function.
*

View File

@@ -447,21 +447,6 @@ BuiltinServiceReference getBuiltinServiceOfKind(string kind) {
)
}
/**
* DEPRECATED: Use `ServiceRequestNode` instead.
* A request for one or more AngularJS services.
*/
deprecated class ServiceRequest extends Expr {
ServiceRequestNode node;
ServiceRequest() { this.flow() = node }
/** Gets the parameter of this request into which `service` is injected. */
deprecated Parameter getDependencyParameter(ServiceReference service) {
result.flow() = node.getDependencyParameter(service)
}
}
/**
* A request for one or more AngularJS services.
*/

View File

@@ -118,8 +118,6 @@ module Connect {
override string getCredentialsKind() { result = kind }
}
deprecated class RequestExpr = NodeJSLib::RequestExpr;
class RequestNode = NodeJSLib::RequestNode;
/**

View File

@@ -5,23 +5,6 @@
import javascript
/**
* DEPRECATED: Use `CredentialsNode` instead.
* An expression whose value is used to supply credentials such
* as a user name, a password, or a key.
*/
deprecated class CredentialsExpr extends Expr {
CredentialsNode node;
CredentialsExpr() { node.asExpr() = this }
/**
* Gets a description of the kind of credential this expression is used as,
* such as `"user name"`, `"password"`, `"key"`.
*/
deprecated string getCredentialsKind() { result = node.getCredentialsKind() }
}
/**
* An expression whose value is used to supply credentials such
* as a user name, a password, or a key.

View File

@@ -51,6 +51,7 @@ private module AsmCrypto {
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
DataFlow::Node input;
CryptographicAlgorithm algorithm; // non-functional
DataFlow::PropRead algorithmSelection;
private string algorithmName;
private string methodName;
@@ -68,11 +69,14 @@ private module AsmCrypto {
exists(DataFlow::SourceNode asmCrypto |
asmCrypto = DataFlow::globalVarRef("asmCrypto") and
algorithm.matchesName(algorithmName) and
this = asmCrypto.getAPropertyRead(algorithmName).getAMemberCall(methodName) and
algorithmSelection = asmCrypto.getAPropertyRead(algorithmName) and
this = algorithmSelection.getAMemberCall(methodName) and
input = this.getArgument(0)
)
}
override DataFlow::Node getInitialization() { result = algorithmSelection }
override DataFlow::Node getAnInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
@@ -103,6 +107,7 @@ private module BrowserIdCrypto {
private class Apply extends CryptographicOperation::Range instanceof DataFlow::MethodCallNode {
CryptographicAlgorithm algorithm; // non-functional
DataFlow::CallNode keygen;
Apply() {
/*
@@ -122,8 +127,7 @@ private module BrowserIdCrypto {
*/
exists(
DataFlow::SourceNode mod, DataFlow::Node algorithmNameNode, DataFlow::CallNode keygen,
DataFlow::FunctionNode callback
DataFlow::SourceNode mod, DataFlow::Node algorithmNameNode, DataFlow::FunctionNode callback
|
mod = DataFlow::moduleImport("browserid-crypto") and
keygen = mod.getAMemberCall("generateKeypair") and
@@ -134,6 +138,8 @@ private module BrowserIdCrypto {
)
}
override DataFlow::Node getInitialization() { result = keygen }
override DataFlow::Node getAnInput() { result = super.getArgument(0) }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
@@ -239,6 +245,8 @@ private module NodeJSCrypto {
Apply() { this = instantiation.getAMethodCall(any(string m | m = "update" or m = "write")) }
override DataFlow::Node getInitialization() { result = instantiation }
override DataFlow::Node getAnInput() { result = super.getArgument(0) }
override CryptographicAlgorithm getAlgorithm() { result = instantiation.getAlgorithm() }
@@ -324,7 +332,9 @@ private module CryptoJS {
)
}
private API::CallNode getEncryptionApplication(API::Node input, CryptographicAlgorithm algorithm) {
private API::CallNode getEncryptionApplication(
API::Node input, API::Node algorithmNode, CryptographicAlgorithm algorithm
) {
/*
* ```
* var CryptoJS = require("crypto-js");
@@ -338,11 +348,14 @@ private module CryptoJS {
* Also matches where `CryptoJS.<algorithmName>` has been replaced by `require("crypto-js/<algorithmName>")`
*/
result = getAlgorithmNode(algorithm).getMember("encrypt").getACall() and
algorithmNode = getAlgorithmNode(algorithm) and
result = algorithmNode.getMember("encrypt").getACall() and
input = result.getParameter(0)
}
private API::CallNode getDirectApplication(API::Node input, CryptographicAlgorithm algorithm) {
private API::CallNode getDirectApplication(
API::Node input, API::Node algorithmNode, CryptographicAlgorithm algorithm
) {
/*
* ```
* var CryptoJS = require("crypto-js");
@@ -357,7 +370,8 @@ private module CryptoJS {
* Also matches where `CryptoJS.<algorithmName>` has been replaced by `require("crypto-js/<algorithmName>")`
*/
result = getAlgorithmNode(algorithm).getACall() and
algorithmNode = getAlgorithmNode(algorithm) and
result = algorithmNode.getACall() and
input = result.getParameter(0)
}
@@ -389,18 +403,23 @@ private module CryptoJS {
private class Apply extends CryptographicOperation::Range instanceof API::CallNode {
API::Node input;
CryptographicAlgorithm algorithm; // non-functional
DataFlow::Node instantiation;
Apply() {
this = getEncryptionApplication(input, algorithm)
or
this = getDirectApplication(input, algorithm)
or
exists(InstantiatedAlgorithm instantiation |
this = getUpdatedApplication(input, instantiation) and
algorithm = instantiation.getAlgorithm()
exists(API::Node algorithmNode |
this = getEncryptionApplication(input, algorithmNode, algorithm)
or
this = getDirectApplication(input, algorithmNode, algorithm)
|
instantiation = algorithmNode.asSource()
)
or
this = getUpdatedApplication(input, instantiation) and
algorithm = instantiation.(InstantiatedAlgorithm).getAlgorithm()
}
override DataFlow::Node getInitialization() { result = instantiation }
override DataFlow::Node getAnInput() { result = input.asSink() }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
@@ -504,6 +523,8 @@ private module TweetNaCl {
)
}
override DataFlow::Node getInitialization() { result = this }
override DataFlow::Node getAnInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
@@ -539,6 +560,7 @@ private module HashJs {
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
DataFlow::Node input;
CryptographicAlgorithm algorithm; // non-functional
DataFlow::CallNode init;
Apply() {
/*
@@ -554,10 +576,13 @@ private module HashJs {
* Also matches where `hash.<algorithmName>()` has been replaced by a more specific require a la `require("hash.js/lib/hash/sha/512")`
*/
this = getAlgorithmNode(algorithm).getAMemberCall("update") and
init = getAlgorithmNode(algorithm) and
this = init.getAMemberCall("update") and
input = super.getArgument(0)
}
override DataFlow::Node getInitialization() { result = init }
override DataFlow::Node getAnInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
@@ -653,6 +678,8 @@ private module Forge {
algorithm = cipher.getAlgorithm()
}
override DataFlow::Node getInitialization() { result = cipher }
override DataFlow::Node getAnInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
@@ -715,6 +742,8 @@ private module Md5 {
super.getArgument(0) = input
}
override DataFlow::Node getInitialization() { result = this }
override DataFlow::Node getAnInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
@@ -731,17 +760,18 @@ private module Bcrypt {
private class Apply extends CryptographicOperation::Range instanceof DataFlow::CallNode {
DataFlow::Node input;
CryptographicAlgorithm algorithm;
API::Node init;
Apply() {
// `require("bcrypt").hash(password);` with minor naming variations
algorithm.matchesName("BCRYPT") and
this =
API::moduleImport(["bcrypt", "bcryptjs", "bcrypt-nodejs"])
.getMember(["hash", "hashSync"])
.getACall() and
init = API::moduleImport(["bcrypt", "bcryptjs", "bcrypt-nodejs"]) and
this = init.getMember(["hash", "hashSync"]).getACall() and
super.getArgument(0) = input
}
override DataFlow::Node getInitialization() { result = init.asSource() }
override DataFlow::Node getAnInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }
@@ -769,6 +799,8 @@ private module Hasha {
)
}
override DataFlow::Node getInitialization() { result = this }
override DataFlow::Node getAnInput() { result = input }
override CryptographicAlgorithm getAlgorithm() { result = algorithm }

View File

@@ -55,14 +55,6 @@ module Express {
WebpackDevServer::webpackDevServerApp().flowsTo(e)
}
/**
* DEPRECATED: Use `RouterDefinition.ref()` or `RouteSetup` instead.
* An expression that refers to a route.
*/
deprecated class RouteExpr extends MethodCallExpr {
RouteExpr() { isRouter(this.flow()) }
}
/**
* Gets the name of an Express router method that sets up a route.
*/
@@ -145,17 +137,6 @@ module Express {
/** Holds if this is a call `use`, such as `app.use(handler)`. */
predicate isUseCall() { this.getMethodName() = "use" }
/**
* DEPRECATED: Use `getRouteHandlerNode` instead.
* Gets the `n`th handler registered by this setup, with 0 being the first.
*
* This differs from `getARouteHandler` in that the argument expression is
* returned, not its dataflow source.
*/
deprecated Expr getRouteHandlerExpr(int index) {
result = this.getRouteHandlerNode(index).asExpr()
}
/**
* Gets the `n`th handler registered by this setup, with 0 being the first.
*
@@ -174,25 +155,11 @@ module Express {
)
}
/**
* DEPRECATED: Use `getARouteHandlerNode` instead.
* Gets an argument that represents a route handler being registered.
*/
deprecated Expr getARouteHandlerExpr() { result = this.getRouteHandlerExpr(_) }
/**
* Gets an argument that represents a route handler being registered.
*/
DataFlow::Node getARouteHandlerNode() { result = this.getRouteHandlerNode(_) }
/**
* DEPRECATED: Use `getLastRouteHandlerExpr` instead.
* Gets the last argument representing a route handler being registered.
*/
deprecated Expr getLastRouteHandlerExpr() {
result = max(int i | | this.getRouteHandlerExpr(i) order by i)
}
/**
* Gets the last argument representing a route handler being registered.
*/
@@ -294,52 +261,6 @@ module Express {
}
}
/**
* DEPRECATED: Use `RouteHandlerNode` instead.
* An expression used as an Express route handler, such as `submitHandler` below:
* ```
* app.post('/submit', submitHandler)
* ```
*
* Unlike `RouterHandler`, this is the argument passed to a setup, as opposed to
* a function that flows into such an argument.
*/
deprecated class RouteHandlerExpr extends Expr {
RouteHandlerNode node;
RouteHandlerExpr() { this.flow() = node }
/** Gets the setup call that registers this route handler. */
deprecated RouteSetup getSetup() { result = node.getSetup() }
/** Gets the function body of this handler, if it is defined locally. */
deprecated RouteHandler getBody() { result = node.getBody() }
/** Holds if this is not followed by more handlers. */
deprecated predicate isLastHandler() { node.isLastHandler() }
/** Gets a route handler that immediately precedes this in the route stack. */
deprecated Express::RouteHandlerExpr getPreviousMiddleware() {
result = node.getPreviousMiddleware().asExpr()
}
/** Gets a route handler that may follow immediately after this one in its route stack. */
deprecated Express::RouteHandlerExpr getNextMiddleware() {
result = node.getNextMiddleware().asExpr()
}
/**
* Gets a route handler that precedes this one (not necessarily immediately), may handle
* same request method, and matches on the same path or a prefix.
*/
deprecated Express::RouteHandlerExpr getAMatchingAncestor() {
result = node.getAMatchingAncestor().asExpr()
}
/** Gets the router being registered as a sub-router here, if any. */
deprecated RouterDefinition getAsSubRouter() { result = node.getAsSubRouter() }
}
/**
* An expression used as an Express route handler, such as `submitHandler` below:
* ```
@@ -584,14 +505,6 @@ module Express {
override RouteHandler getRouteHandler() { none() } // Not known.
}
/**
* DEPRECATED: Use `ResponseNode` instead.
* An Express response expression.
*/
deprecated class ResponseExpr extends NodeJSLib::ResponseExpr {
ResponseExpr() { this.flow() instanceof ResponseNode }
}
/**
* An Express response expression.
*/
@@ -599,14 +512,6 @@ module Express {
override ResponseSource src;
}
/**
* DEPRECATED: Use `RequestNode` instead.
* An Express request expression.
*/
deprecated class RequestExpr extends NodeJSLib::RequestExpr {
RequestExpr() { this.flow() instanceof RequestNode }
}
/**
* An Express request expression.
*/
@@ -713,6 +618,10 @@ module Express {
or
kind = "body" and
this = ref.getAPropertyRead("body")
or
// `req.path`
kind = "url" and
this = ref.getAPropertyRead("path")
)
}

View File

@@ -154,12 +154,6 @@ module Fastify {
override DataFlow::SourceNode getServer() { result = server }
/**
* DEPRECATED: Use `getARouteHandlerNode` instead.
* Gets an argument that represents a route handler being registered.
*/
deprecated DataFlow::Node getARouteHandlerExpr() { result = this.getARouteHandlerNode() }
/** Gets an argument that represents a route handler being registered. */
DataFlow::Node getARouteHandlerNode() {
if methodName = "route"

View File

@@ -65,23 +65,9 @@ module Http {
)
}
/**
* DEPRECATED: use `definesHeaderValue` instead.
* Holds if the header with (lower-case) name `headerName` is set to the value of `headerValue`.
*/
deprecated predicate definesExplicitly(string headerName, Expr headerValue) {
this.definesHeaderValue(headerName, headerValue.flow())
}
/** Holds if the header with (lower-case) name `headerName` is set to the value of `headerValue`. */
abstract predicate definesHeaderValue(string headerName, DataFlow::Node headerValue);
/**
* DEPRECATED: Use `getNameNode()` instead.
* Returns the expression used to compute the header name.
*/
deprecated Expr getNameExpr() { result = this.getNameNode().asExpr() }
/** Returns the expression used to compute the header name. */
abstract DataFlow::Node getNameNode();
}
@@ -202,26 +188,12 @@ module Http {
*/
final Servers::ResponseSource getAResponseSource() { result.getRouteHandler() = this }
/**
* DEPRECATED: Use `getARequestNode()` instead.
* Gets an expression that contains a request object handled
* by this handler.
*/
deprecated RequestExpr getARequestExpr() { result.flow() = this.getARequestNode() }
/**
* Gets an expression that contains a request object handled
* by this handler.
*/
RequestNode getARequestNode() { result.getRouteHandler() = this }
/**
* DEPRECATED: Use `getAResponseNode()` instead.
* Gets an expression that contains a response object provided
* by this handler.
*/
deprecated ResponseExpr getAResponseExpr() { result.flow() = this.getAResponseNode() }
/**
* Gets an expression that contains a response object provided
* by this handler.
@@ -265,30 +237,6 @@ module Http {
abstract RouteHandler getRouteHandler();
}
/**
* DEPRECATED: Use `RequestNode` instead.
* An expression that may contain a request object.
*/
deprecated class RequestExpr extends Expr {
RequestExpr() { this.flow() instanceof ResponseNode }
/**
* Gets the route handler that handles this request.
*/
RouteHandler getRouteHandler() { result = this.flow().(ResponseNode).getRouteHandler() }
}
/**
* DEPRECATED: Use `ResponseNode` instead.
* An expression that may contain a response object.
*/
deprecated class ResponseExpr extends Expr {
/**
* Gets the route handler that handles this request.
*/
RouteHandler getRouteHandler() { result = this.flow().(ResponseNode).getRouteHandler() }
}
/**
* Boiler-plate implementation of a `Server` and its associated classes.
* Made for easily defining new HTTP servers
@@ -309,12 +257,6 @@ module Http {
/** Gets a data flow node referring to this server. */
DataFlow::SourceNode ref() { result = this.ref(DataFlow::TypeTracker::end()) }
/**
* DEPRECATED: Use `ref().flowsToExpr()` instead.
* Holds if `sink` may refer to this server definition.
*/
deprecated predicate flowsTo(Expr sink) { this.ref().flowsToExpr(sink) }
}
/**
@@ -402,30 +344,6 @@ module Http {
override RouteHandler getRouteHandler() { result = src.getRouteHandler() }
}
/**
* A request expression arising from a request source.
*/
deprecated class StandardRequestExpr extends RequestExpr {
RequestSource src;
StandardRequestExpr() { src.ref().flowsToExpr(this) }
override RouteHandler getRouteHandler() { result = src.getRouteHandler() }
}
/**
* A response expression arising from a response source.
*/
deprecated class StandardResponseExpr extends ResponseExpr {
ResponseSource src;
StandardResponseExpr() { src.ref().flowsToExpr(this) }
override RouteHandler getRouteHandler() {
result = this.flow().(StandardResponseNode).getRouteHandler()
}
}
/**
* A standard header definition.
*/

View File

@@ -87,14 +87,6 @@ module Hapi {
override RouteHandler getRouteHandler() { result = rh }
}
/**
* DEPRECATED: Use `ResponseNode` instead.
* A Hapi response expression.
*/
deprecated class ResponseExpr extends HTTP::Servers::StandardResponseExpr {
ResponseExpr() { this.flow() instanceof ResponseNode }
}
/**
* A Hapi response node.
*/
@@ -102,14 +94,6 @@ module Hapi {
override ResponseSource src;
}
/**
* DEPRECATED: Use `RequestNode` instead.
* An Hapi request expression.
*/
deprecated class RequestExpr extends HTTP::Servers::StandardRequestExpr {
RequestExpr() { this.flow() instanceof RequestNode }
}
/**
* A Hapi request node.
*/
@@ -255,8 +239,6 @@ module Hapi {
pragma[noinline]
private DataFlow::Node getRouteHandler() { result = handler }
deprecated Expr getRouteHandlerExpr() { result = handler.asExpr() }
override DataFlow::Node getServer() { result = server }
}

View File

@@ -44,13 +44,6 @@ module Koa {
result = this.getAFunctionValue().getParameter(0)
}
/**
* DEPRECATED: Use `getAContextNode` instead.
* Gets an expression that contains the "context" object of
* a route handler invocation.
*/
deprecated Expr getAContextExpr() { result = this.getAContextNode().asExpr() }
/**
* Gets an expression that contains the "context" object of
* a route handler invocation.
@@ -61,15 +54,6 @@ module Koa {
*/
DataFlow::Node getAContextNode() { result.(ContextNode).getRouteHandler() = this }
/**
* DEPRECATED: Use `getAResponseOrContextNode` instead.
* Gets an expression that contains the context or response
* object of a route handler invocation.
*/
deprecated Expr getAResponseOrContextExpr() {
result = this.getAResponseOrContextNode().asExpr()
}
/**
* Gets an expression that contains the context or response
* object of a route handler invocation.
@@ -78,13 +62,6 @@ module Koa {
result = this.getAResponseNode() or result = this.getAContextNode()
}
/**
* DEPRECATED: Use `getARequestOrContextNode` instead.
* Gets an expression that contains the context or request
* object of a route handler invocation.
*/
deprecated Expr getARequestOrContextExpr() { result = this.getARequestOrContextNode().asExpr() }
/**
* Gets an expression that contains the context or request
* object of a route handler invocation.
@@ -273,19 +250,6 @@ module Koa {
override RouteHandler getRouteHandler() { result = ctx.getRouteHandler() }
}
/**
* DEPRECATED: Use `ContextNode` instead.
* An expression that may hold a Koa context object.
*/
deprecated class ContextExpr extends Expr {
ContextNode node;
ContextExpr() { node.asExpr() = this }
/** Gets the route handler that provides this response. */
deprecated RouteHandler getRouteHandler() { result = node.getRouteHandler() }
}
/**
* An expression that may hold a Koa context object.
*/
@@ -300,14 +264,6 @@ module Koa {
RouteHandler getRouteHandler() { result = src.getRouteHandler() }
}
/**
* DEPRECATED: Use `RequestNode` instead.
* An expression that may hold a Koa request object.
*/
deprecated class RequestExpr extends HTTP::Servers::StandardRequestExpr {
RequestExpr() { this.flow() instanceof RequestNode }
}
/**
* An expression that may hold a Koa request object.
*/
@@ -315,14 +271,6 @@ module Koa {
override RequestSource src;
}
/**
* DEPRECATED: Use `ResponseNode` instead.
* An expression that may hold a Koa response object.
*/
deprecated class ResponseExpr extends HTTP::Servers::StandardResponseExpr {
ResponseExpr() { this.flow() instanceof ResponseNode }
}
/**
* An expression that may hold a Koa response object.
*/

View File

@@ -62,18 +62,10 @@ private module Micro {
override Http::RouteHandler getRouteHandler() { result = h }
}
deprecated class MicroRequestExpr extends NodeJSLib::RequestExpr {
override MicroRequestSource src;
}
class MicroRequestNode extends NodeJSLib::RequestNode {
override MicroRequestSource src;
}
deprecated class MicroReseponseExpr extends NodeJSLib::ResponseExpr {
override MicroResponseSource src;
}
class MicroResponseNode extends NodeJSLib::ResponseNode {
override MicroResponseSource src;
}

View File

@@ -64,17 +64,6 @@ module NodeJSLib {
)
}
/**
* DEPRECATED: Use `ResponseNode` instead.
* A Node.js HTTP response.
*
* A server library that provides an (enhanced) NodesJS HTTP response
* object should implement a library specific subclass of this class.
*/
deprecated class ResponseExpr extends HTTP::Servers::StandardResponseExpr {
ResponseExpr() { this.flow() instanceof ResponseNode }
}
/**
* A Node.js HTTP response.
*
@@ -83,17 +72,6 @@ module NodeJSLib {
*/
abstract class ResponseNode extends Http::Servers::StandardResponseNode { }
/**
* DEPRECATED: Use `RequestNode` instead.
* A Node.js HTTP request.
*
* A server library that provides an (enhanced) NodesJS HTTP request
* object should implement a library specific subclass of this class.
*/
deprecated class RequestExpr extends HTTP::Servers::StandardRequestExpr {
RequestExpr() { this.flow() instanceof RequestNode }
}
/**
* A Node.js HTTP request.
*
@@ -168,14 +146,6 @@ module NodeJSLib {
override RouteHandler getRouteHandler() { result = rh }
}
/**
* DEPRECATED: Use `BuiltinRouteHandlerResponseNode` instead.
* A builtin Node.js HTTP response.
*/
deprecated private class BuiltinRouteHandlerResponseExpr extends ResponseExpr {
BuiltinRouteHandlerResponseExpr() { src instanceof ResponseSource }
}
/**
* A builtin Node.js HTTP response.
*/
@@ -183,14 +153,6 @@ module NodeJSLib {
BuiltinRouteHandlerResponseNode() { src instanceof ResponseSource }
}
/**
* DEPRECATED: Use `BuiltinRouteHandlerRequestNode` instead.
* A builtin Node.js HTTP request.
*/
deprecated private class BuiltinRouteHandlerRequestExpr extends RequestExpr {
BuiltinRouteHandlerRequestExpr() { src instanceof RequestSource }
}
/**
* A builtin Node.js HTTP request.
*/
@@ -288,12 +250,6 @@ module NodeJSLib {
override DataFlow::Node getServer() { result = server }
/**
* DEPRECATED: Use `getRouteHandlerNode` instead.
* Gets the expression for the handler registered by this setup.
*/
deprecated Expr getRouteHandlerExpr() { result = handler.asExpr() }
/**
* Gets the expression for the handler registered by this setup.
*/

View File

@@ -72,14 +72,6 @@ module Restify {
override RouteHandler getRouteHandler() { result = rh }
}
/**
* DEPRECATED: Use `ResponseNode` instead.
* A Node.js HTTP response provided by Restify.
*/
deprecated class ResponseExpr extends NodeJSLib::ResponseExpr {
ResponseExpr() { src instanceof ResponseSource }
}
/**
* A Node.js HTTP response provided by Restify.
*/
@@ -87,14 +79,6 @@ module Restify {
ResponseNode() { src instanceof ResponseSource or src instanceof FormatterResponseSource }
}
/**
* DEPRECATED: Use `RequestNode` instead.
* A Node.js HTTP request provided by Restify.
*/
deprecated class RequestExpr extends NodeJSLib::RequestExpr {
RequestExpr() { src instanceof RequestSource }
}
/**
* A Node.js HTTP request provided by Restify.
*/

View File

@@ -17,7 +17,7 @@ extensible predicate sourceModel(string type, string path, string kind);
extensible predicate sinkModel(string type, string path, string kind);
/**
* Holds if calls to `(type, path)`, the value referred to by `input`
* Holds if in calls to `(type, path)`, the value referred to by `input`
* can flow to the value referred to by `output`.
*
* `kind` should be either `value` or `taint`, for value-preserving or taint-preserving steps,
@@ -25,6 +25,13 @@ extensible predicate sinkModel(string type, string path, string kind);
*/
extensible predicate summaryModel(string type, string path, string input, string output, string kind);
/**
* Holds if calls to `(type, path)` should be considered neutral. The meaning of this depends on the `kind`.
* If `kind` is `summary`, the call does not propagate data flow. If `kind` is `source`, the call is not a source.
* If `kind` is `sink`, the call is not a sink.
*/
extensible predicate neutralModel(string type, string path, string kind);
/**
* Holds if `(type2, path)` should be seen as an instance of `type1`.
*/

View File

@@ -15,6 +15,11 @@ extensions:
extensible: summaryModel
data: []
- addsTo:
pack: codeql/javascript-all
extensible: neutralModel
data: []
- addsTo:
pack: codeql/javascript-all
extensible: typeModel

View File

@@ -145,6 +145,12 @@ module Stages {
exists(any(DataFlow::PropRef ref).getBase())
or
exists(any(DataFlow::ClassNode cls))
or
exists(any(DataFlow::CallNode node).getArgument(_))
or
exists(any(DataFlow::CallNode node).getAnArgument())
or
exists(any(DataFlow::CallNode node).getLastArgument())
}
}

View File

@@ -40,6 +40,9 @@ module Cryptography {
/** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */
CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() }
/** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */
DataFlow::Node getInitialization() { result = super.getInitialization() }
/** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */
DataFlow::Node getAnInput() { result = super.getAnInput() }
@@ -65,6 +68,9 @@ module Cryptography {
* extend `CryptographicOperation` instead.
*/
abstract class Range extends DataFlow::Node {
/** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */
abstract DataFlow::Node getInitialization();
/** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */
abstract CryptographicAlgorithm getAlgorithm();

View File

@@ -13,22 +13,6 @@ import javascript
import semmle.javascript.security.internal.SensitiveDataHeuristics
private import HeuristicNames
/**
* DEPRECATED: Use `SensitiveNode` instead.
* An expression that might contain sensitive data.
*/
deprecated class SensitiveExpr extends Expr {
SensitiveNode node;
SensitiveExpr() { node.asExpr() = this }
/** Gets a human-readable description of this expression for use in alert messages. */
deprecated string describe() { result = node.describe() }
/** Gets a classification of the kind of sensitive data this expression might contain. */
deprecated SensitiveDataClassification getClassification() { result = node.getClassification() }
}
/** An expression that might contain sensitive data. */
cached
abstract class SensitiveNode extends DataFlow::Node {

View File

@@ -19,7 +19,10 @@ module BrokenCryptoAlgorithm {
/**
* A data flow sink for sensitive information in broken or weak cryptographic algorithms.
*/
abstract class Sink extends DataFlow::Node { }
abstract class Sink extends DataFlow::Node {
/** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */
abstract DataFlow::Node getInitialization();
}
/**
* A sanitizer for sensitive information in broken or weak cryptographic algorithms.
@@ -38,15 +41,17 @@ module BrokenCryptoAlgorithm {
* An expression used by a broken or weak cryptographic algorithm.
*/
class WeakCryptographicOperationSink extends Sink {
CryptographicOperation application;
WeakCryptographicOperationSink() {
exists(CryptographicOperation application |
(
application.getAlgorithm().isWeak()
or
application.getBlockMode().isWeak()
) and
this = application.getAnInput()
)
(
application.getAlgorithm().isWeak()
or
application.getBlockMode().isWeak()
) and
this = application.getAnInput()
}
override DataFlow::Node getInitialization() { result = application.getInitialization() }
}
}

View File

@@ -18,23 +18,11 @@ class DomGlobalVariable extends GlobalVariable {
}
}
/**
* DEPRECATED: Use `isDomNode` instead.
* Holds if `e` could hold a value that comes from the DOM.
*/
deprecated predicate isDomValue(Expr e) { isDomNode(e.flow()) }
/**
* Holds if `e` could hold a value that comes from the DOM.
*/
predicate isDomNode(DataFlow::Node e) { DOM::domValueRef().flowsTo(e) }
/**
* DEPRECATED: Use `isLocationNode` instead.
* Holds if `e` could refer to the `location` property of a DOM node.
*/
deprecated predicate isLocation(Expr e) { isLocationNode(e.flow()) }
/** Holds if `e` could refer to the `location` property of a DOM node. */
predicate isLocationNode(DataFlow::Node e) {
e = DOM::domValueRef().getAPropertyReference("location")
@@ -42,43 +30,6 @@ predicate isLocationNode(DataFlow::Node e) {
e = DataFlow::globalVarRef("location")
}
/**
* DEPRECATED. In most cases, a sanitizer based on this predicate can be removed, as
* taint tracking no longer step through the properties of the location object by default.
*
* Holds if `pacc` accesses a part of `document.location` that is
* not considered user-controlled, that is, anything except
* `href`, `hash` and `search`.
*/
deprecated predicate isSafeLocationProperty(PropAccess pacc) {
exists(string prop | pacc = DOM::locationRef().getAPropertyRead(prop).asExpr() |
prop != "href" and prop != "hash" and prop != "search"
)
}
/**
* DEPRECATED: Use `DomMethodCallNode` instead.
* A call to a DOM method.
*/
deprecated class DomMethodCallExpr extends MethodCallExpr {
DomMethodCallNode node;
DomMethodCallExpr() { this.flow() = node }
/** Holds if `arg` is an argument that is interpreted as HTML. */
deprecated predicate interpretsArgumentsAsHtml(Expr arg) {
node.interpretsArgumentsAsHtml(arg.flow())
}
/** Holds if `arg` is an argument that is used as an URL. */
deprecated predicate interpretsArgumentsAsURL(Expr arg) {
node.interpretsArgumentsAsURL(arg.flow())
}
/** DEPRECATED: Alias for interpretsArgumentsAsHtml */
deprecated predicate interpretsArgumentsAsHTML(Expr arg) { this.interpretsArgumentsAsHtml(arg) }
}
/**
* A call to a DOM method.
*/
@@ -129,36 +80,6 @@ class DomMethodCallNode extends DataFlow::MethodCallNode {
)
)
}
/** DEPRECATED: Alias for interpretsArgumentsAsUrl */
deprecated predicate interpretsArgumentsAsURL(DataFlow::Node arg) {
this.interpretsArgumentsAsUrl(arg)
}
/** DEPRECATED: Alias for interpretsArgumentsAsHtml */
deprecated predicate interpretsArgumentsAsHTML(DataFlow::Node arg) {
this.interpretsArgumentsAsHtml(arg)
}
}
/**
* DEPRECATED: Use `DomPropertyWrite` instead.
* An assignment to a property of a DOM object.
*/
deprecated class DomPropWriteNode extends Assignment {
DomPropertyWrite node;
DomPropWriteNode() { this.flow() = node }
/**
* Holds if the assigned value is interpreted as HTML.
*/
predicate interpretsValueAsHtml() { node.interpretsValueAsHtml() }
/**
* Holds if the assigned value is interpreted as JavaScript via javascript: protocol.
*/
predicate interpretsValueAsJavaScriptUrl() { node.interpretsValueAsJavaScriptUrl() }
}
/**

View File

@@ -120,9 +120,6 @@ module DomBasedXss {
WriteUrlSink() { super.isXssSink() }
}
/** DEPRECATED: Alias for `WriteUrlSink`. */
deprecated class WriteURLSink = WriteUrlSink;
/**
* An expression whose value is interpreted as HTML or CSS
* and may be inserted into the DOM.

View File

@@ -114,7 +114,13 @@ abstract class RateLimitingMiddleware extends DataFlow::SourceNode {
* A rate limiter constructed using the `express-rate-limit` package.
*/
class ExpressRateLimit extends RateLimitingMiddleware {
ExpressRateLimit() { this = API::moduleImport("express-rate-limit").getReturn().asSource() }
ExpressRateLimit() {
this =
[
API::moduleImport("express-rate-limit"),
API::moduleImport("express-rate-limit").getMember("rateLimit")
].getReturn().asSource()
}
}
/**

View File

@@ -9,11 +9,14 @@ private import semmle.javascript.security.dataflow.UnsafeJQueryPluginCustomizati
import UnsafeHtmlConstructionCustomizations::UnsafeHtmlConstruction
import semmle.javascript.security.TaintedObject
/** DEPRECATED: Mis-spelled class name, alias for Configuration. */
deprecated class Configration = Configuration;
/**
* A taint-tracking configuration for reasoning about unsafe HTML constructed from library input vulnerabilities.
*/
class Configration extends TaintTracking::Configuration {
Configration() { this = "UnsafeHtmlConstruction" }
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "UnsafeHtmlConstruction" }
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
source instanceof Source and

View File

@@ -20,6 +20,13 @@ module Shared {
string getVulnerabilityKind() { result = "Cross-site scripting" }
}
// import the various XSS query customizations, they populate the shared classes
private import DomBasedXssCustomizations
private import ReflectedXssCustomizations
private import StoredXssCustomizations
private import XssThroughDomCustomizations
private import ExceptionXssCustomizations
/** A sanitizer for XSS vulnerabilities. */
abstract class Sanitizer extends DataFlow::Node { }
@@ -138,43 +145,3 @@ module Shared {
IsEscapedInSwitchSanitizer() { this.asExpr() = getAPathEscapedInSwitch().getAUse() }
}
}
/**
* DEPRECATED: Use the `DomBasedXssCustomizations.qll` file instead.
* Provides classes and predicates for the DOM-based XSS query.
*/
deprecated module DomBasedXss {
import DomBasedXssCustomizations::DomBasedXss
}
/**
* DEPRECATED: Use the `DomBasedXssCustomizations.qll` file instead.
* Provides classes and predicates for the reflected XSS query.
*/
deprecated module ReflectedXss {
import ReflectedXssCustomizations::ReflectedXss
}
/**
* DEPRECATED: Use the `StoredXssCustomizations.qll` file instead.
* Provides classes and predicates for the stored XSS query.
*/
deprecated module StoredXss {
import StoredXssCustomizations::StoredXss
}
/**
* DEPRECATED: Use the `XssThroughDomCustomizations.qll` file instead.
* Provides classes and predicates for the XSS through DOM query.
*/
deprecated module XssThroughDom {
import XssThroughDomCustomizations::XssThroughDom
}
/**
* DEPRECATED: Use the `ExceptionXssCustomizations.qll` file instead.
* Provides classes for customizing the `ExceptionXss` query.
*/
deprecated module ExceptionXss {
import ExceptionXssCustomizations::ExceptionXss
}

View File

@@ -1,4 +0,0 @@
/** DEPRECATED. Import `semmle.javascript.security.regexp.ExponentialBackTracking` instead. */
deprecated private import semmle.javascript.security.regexp.ExponentialBackTracking as Dep
import Dep

View File

@@ -1,7 +0,0 @@
/** DEPRECATED. Import `PolynomialReDoSQuery` instead. */
import javascript
private import semmle.javascript.security.regexp.PolynomialReDoSQuery as PolynomialReDoSQuery // ignore-query-import
/** DEPRECATED. Import `PolynomialReDoSQuery` instead. */
deprecated module PolynomialReDoS = PolynomialReDoSQuery;

View File

@@ -1,4 +0,0 @@
/** DEPRECATED. Import `semmle.javascript.security.regexp.PolynomialReDoSCustomizations` instead. */
deprecated private import semmle.javascript.security.regexp.PolynomialReDoSCustomizations as Dep
import Dep

View File

@@ -1,4 +0,0 @@
/** DEPRECATED. Import `semmle.javascript.security.regexp.NfaUtils` instead. */
deprecated private import semmle.javascript.security.regexp.NfaUtils as Dep
import Dep

View File

@@ -1,4 +0,0 @@
/** DEPRECATED. Import `semmle.javascript.security.regexp.SuperlinearBackTracking` instead. */
deprecated private import semmle.javascript.security.regexp.SuperlinearBackTracking as Dep
import Dep

View File

@@ -3,7 +3,7 @@
*
* James Kirrage, Asiri Rathnayake, Hayo Thielecke: Static Analysis for
* Regular Expression Denial-of-Service Attacks. NSS 2013.
* (http://www.cs.bham.ac.uk/~hxt/research/reg-exp-sec.pdf)
* (https://arxiv.org/abs/1301.0849)
* Asiri Rathnayake, Hayo Thielecke: Static Analysis for Regular Expression
* Exponential Runtime via Substructural Logics. 2014.
* (https://www.cs.bham.ac.uk/~hxt/research/redos_full.pdf)

View File

@@ -162,9 +162,10 @@ case @stmt.kind of
| 37 = @external_module_declaration
| 38 = @export_as_namespace_declaration
| 39 = @global_augmentation_declaration
| 40 = @using_decl_stmt
;
@decl_stmt = @var_decl_stmt | @const_decl_stmt | @let_stmt | @legacy_let_stmt;
@decl_stmt = @var_decl_stmt | @const_decl_stmt | @let_stmt | @legacy_let_stmt | @using_decl_stmt;
@export_declaration = @export_all_declaration | @export_default_declaration | @export_named_declaration;

View File

@@ -170,6 +170,10 @@
<v>5</v>
</e>
<e>
<k>@using_decl_stmt</k>
<v>5</v>
</e>
<e>
<k>@export_default_declaration</k>
<v>5</v>
</e>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: add support for TypeScript 5.2
compatibility: backwards

View File

@@ -1,3 +1,47 @@
## 0.8.3
### Query Metadata Changes
* Lower the security severity of log-injection to medium.
* Increase the security severity of XSS to high.
## 0.8.2
### Minor Analysis Improvements
* Added modeling for importing `express-rate-limit` using a named import.
## 0.8.1
### Minor Analysis Improvements
* Added the `AmdModuleDefinition::Range` class, making it possible to define custom aliases for the AMD `define` function.
## 0.8.0
No user-facing changes.
## 0.7.5
### Bug Fixes
* Fixed an extractor crash that could occur in projects containing TypeScript files larger than 10 MB.
## 0.7.4
### Minor Analysis Improvements
* Files larger than 10 MB are no longer be extracted or analyzed.
* Imports can now be resolved in more cases, where a non-constant string expression is passed to a `require()` call.
### Bug Fixes
* Fixed an extractor crash that would occur in rare cases when a TypeScript file contains a self-referential namespace alias.
## 0.7.3
No user-facing changes.
## 0.7.2
No user-facing changes.

View File

@@ -13,8 +13,9 @@
import javascript
import semmle.javascript.RestrictedLocations
from ConstDeclStmt cds, VariableDeclarator decl, VarDef def, Variable v
from DeclStmt cds, VariableDeclarator decl, VarDef def, Variable v
where
(cds instanceof ConstDeclStmt or cds instanceof UsingDeclStmt) and
decl = cds.getADecl() and
def.getAVariable() = v and
decl.getBindingPattern().getAVariable() = v and

View File

@@ -10,7 +10,7 @@
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/ReDoS">ReDoS</a>.</li>
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Time_complexity">Time complexity</a>.</li>
<li>James Kirrage, Asiri Rathnayake, Hayo Thielecke:
<a href="http://www.cs.bham.ac.uk/~hxt/research/reg-exp-sec.pdf">Static Analysis for Regular Expression Denial-of-Service Attack</a>.
<a href="https://arxiv.org/abs/1301.0849">Static Analysis for Regular Expression Denial-of-Service Attack</a>.
</li>
</references>
</qhelp>

View File

@@ -3,7 +3,7 @@
* @description Replacing a substring with itself has no effect and may indicate a mistake.
* @kind problem
* @problem.severity warning
* @security-severity 7.8
* @security-severity 5.0
* @id js/identity-replacement
* @precision very-high
* @tags correctness

View File

@@ -13,40 +13,47 @@ attacker being able to influence behavior by modifying unexpected files.
<recommendation>
<p>
Validate user input before using it to construct a file path, either using an off-the-shelf library
like the <code>sanitize-filename</code> npm package, or by performing custom validation.
Validate user input before using it to construct a file path.
</p>
<p>
Ideally, follow these rules:
The validation method you should use depends on whether you want to allow the user to specify complex paths with multiple components that may span multiple folders, or only simple filenames without a path component.
</p>
<ul>
<li>Do not allow more than a single "." character.</li>
<li>Do not allow directory separators such as "/" or "\" (depending on the file system).</li>
<li>Do not rely on simply replacing problematic sequences such as "../". For example, after
applying this filter to ".../...//", the resulting string would still be "../".</li>
<li>Use a whitelist of known good patterns.</li>
</ul>
<p>
In the former case, a common strategy is to make sure that the constructed file path is contained within a safe root folder.
First, normalize the path using <code>path.resolve</code> or <code>fs.realpathSync</code> to remove any ".." segments.
You should always normalize the file path since an unnormalized path that starts with the root folder can still be used to access files outside the root folder.
Then, after you have normalized the path, check that the path starts with the root folder.
</p>
<p>
In the latter case, you can use a library like the <code>sanitize-filename</code> npm package to eliminate any special characters from the file path.
Note that it is <i>not</i> sufficient to only remove "../" sequences: for example, applying this filter to ".../...//" would still result in the string "../".
</p>
<p>
Finally, the simplest (but most restrictive) option is to use an allow list of safe patterns and make sure that the user input matches one of these patterns.
</p>
</recommendation>
<example>
<p>
In the first example, a file name is read from an HTTP request and then used to access a file.
However, a malicious user could enter a file name which is an absolute path, such as
<code>"/etc/passwd"</code>.
</p>
<p>
In the second example, it appears that the user is restricted to opening a file within the
<code>"user"</code> home directory. However, a malicious user could enter a file name containing
special characters. For example, the string <code>"../../etc/passwd"</code> will result in the code
reading the file located at <code>"/home/user/../../etc/passwd"</code>, which is the system's
password file. This file would then be sent back to the user, giving them access to all the
system's passwords.
In the first (bad) example, the code reads the file name from an HTTP request, then accesses that file within a root folder.
A malicious user could enter a file name containing "../" segments to navigate outside the root folder and access sensitive files.
</p>
<sample src="examples/TaintedPath.js" />
<p>
The second (good) example shows how to avoid access to sensitive files by sanitizing the file path.
First, the code resolves the file name relative to a root folder, normalizing the path and removing any "../" segments in the process.
Then, the code calls <code>fs.realpathSync</code> to resolve any symbolic links in the path.
Finally, the code checks that the normalized path starts with the path of the root folder, ensuring the file is contained within the root folder.
</p>
<sample src="examples/TaintedPathGood.js" />
</example>
<references>

View File

@@ -1,13 +1,12 @@
var fs = require('fs'),
http = require('http'),
url = require('url');
const fs = require('fs'),
http = require('http'),
url = require('url');
const ROOT = "/var/www/";
var server = http.createServer(function(req, res) {
let path = url.parse(req.url, true).query.path;
let filePath = url.parse(req.url, true).query.path;
// BAD: This could read any file on the file system
res.write(fs.readFileSync(path));
// BAD: This could still read any file on the file system
res.write(fs.readFileSync("/home/user/" + path));
});
// BAD: This function uses unsanitized input that can read any file on the file system.
res.write(fs.readFileSync(ROOT + filePath, 'utf8'));
});

View File

@@ -0,0 +1,19 @@
const fs = require('fs'),
http = require('http'),
path = require('path'),
url = require('url');
const ROOT = "/var/www/";
var server = http.createServer(function(req, res) {
let filePath = url.parse(req.url, true).query.path;
// GOOD: Verify that the file path is under the root directory
filePath = fs.realpathSync(path.resolve(ROOT, filePath));
if (!filePath.startsWith(ROOT)) {
res.statusCode = 403;
res.end();
return;
}
res.write(fs.readFileSync(filePath, 'utf8'));
});

View File

@@ -4,7 +4,7 @@
* a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity error
* @security-severity 6.1
* @security-severity 7.8
* @precision high
* @id js/reflected-xss
* @tags security

View File

@@ -4,7 +4,7 @@
* a stored cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity error
* @security-severity 6.1
* @security-severity 7.8
* @precision high
* @id js/stored-xss
* @tags security

View File

@@ -4,7 +4,7 @@
* a cross-site scripting vulnerability.
* @kind path-problem
* @problem.severity error
* @security-severity 6.1
* @security-severity 7.8
* @precision high
* @id js/xss
* @tags security

View File

@@ -1,8 +1,137 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<include src="IncompleteSanitization.qhelp" />
<overview>
<p>
Sanitizing untrusted input is a common technique for preventing injection attacks and other security
vulnerabilities. Regular expressions are often used to perform this sanitization. However, when the
regular expression matches multiple consecutive characters, replacing it just once
can result in the unsafe text reappearing in the sanitized input.
</p>
<p>
Attackers can exploit this issue by crafting inputs that, when sanitized with an ineffective regular
expression, still contain malicious code or content. This can lead to code execution, data exposure,
or other vulnerabilities.
</p>
</overview>
<recommendation>
<p>
To prevent this issue, it is highly recommended to use a well-tested sanitization library whenever
possible. These libraries are more likely to handle corner cases and ensure effective sanitization.
</p>
<p>
If a library is not an option, you can consider alternative strategies to fix the issue. For example,
applying the regular expression replacement repeatedly until no more replacements can be performed, or rewriting the regular
expression to match single characters instead of the entire unsafe text.
</p>
</recommendation>
<example>
<p>
Consider the following JavaScript code that aims to remove all HTML comment start and end tags:
</p>
<sample language="javascript">
str.replace(/&lt;!--|--!?&gt;/g, "");
</sample>
<p>
Given the input string "&lt;!&lt;!--- comment ---&gt;&gt;", the output will be "&lt;!-- comment --&gt;",
which still contains an HTML comment.
</p>
<p>
One possible fix for this issue is to apply the regular expression replacement repeatedly until no
more replacements can be performed. This ensures that the unsafe text does not re-appear in the sanitized input, effectively
removing all instances of the targeted pattern:
</p>
<sample language="javascript">
function removeHtmlComments(input) {
let previous;
do {
previous = input;
input = input.replace(/&lt;!--|--!?&gt;/g, "");
} while (input !== previous);
return input;
}
</sample>
</example>
<example>
<p>
Another example is the following regular expression intended to remove script tags:
</p>
<sample language="javascript">
str.replace(/&lt;script\b[^&lt;]*(?:(?!&lt;\/script&gt;)&lt;[^&lt;]*)*&lt;\/script&gt;/g, "");
</sample>
<p>
If the input string is "&lt;scrip&lt;script&gt;is removed&lt;/script&gt;t&gt;alert(123)&lt;/script&gt;",
the output will be "&lt;script&gt;alert(123)&lt;/script&gt;", which still contains a script tag.
</p>
<p>
A fix for this issue is to rewrite the regular expression to match single characters
("&lt;" and "&gt;") instead of the entire unsafe text. This simplifies the sanitization process
and ensures that all potentially unsafe characters are removed:
</p>
<sample language="javascript">
function removeAllHtmlTags(input) {
return input.replace(/&lt;|&gt;/g, "");
}
</sample>
<p>
Another potential fix is to use the popular <code>sanitize-html</code> npm library.
It keeps most of the safe HTML tags while removing all unsafe tags and attributes.
</p>
<sample language="javascript">
const sanitizeHtml = require("sanitize-html");
function removeAllHtmlTags(input) {
return sanitizeHtml(input);
}
</sample>
</example>
<example>
<p>
Lastly, consider a path sanitizer using the regular expression <code>/\.\.\//</code>:
</p>
<sample language="javascript">
str.replace(/\.\.\//g, "");
</sample>
<p>
The regular expression attempts to strip out all occurences of <code>/../</code> from <code>str</code>.
This will not work as expected: for the string <code>/./.././</code>, for example, it will remove the single
occurrence of <code>/../</code> in the middle, but the remainder of the string then becomes
<code>/../</code>, which is another instance of the substring we were trying to remove.
</p>
<p>
A possible fix for this issue is to use the "sanitize-filename" npm library for path sanitization.
This library is specifically designed to handle path sanitization, and should handle all corner cases
and ensure effective sanitization:
</p>
<sample language="javascript">
const sanitize = require("sanitize-filename");
function sanitizePath(input) {
return sanitize(input);
}
</sample>
</example>
<references>
<li>OWASP Top 10: <a href="https://www.owasp.org/index.php/Top_10-2017_A1-Injection">A1 Injection</a>.</li>
<li>Stack Overflow: <a href="https://stackoverflow.com/questions/6659351/removing-all-script-tags-from-html-with-js-regular-expression">Removing all script tags from HTML with JS regular expression</a>.</li>
</references>
</qhelp>

View File

@@ -43,18 +43,6 @@ needed, for instance by using prepared statements for SQL queries.
Otherwise, make sure to use a regular expression with the <code>g</code> flag to ensure that
all occurrences are replaced, and remember to escape backslashes if applicable.
</p>
<p>
Note, however, that this is generally <i>not</i> sufficient for replacing multi-character strings:
the <code>String.prototype.replace</code> method only performs one pass over the input string,
and will not replace further instances of the string that result from earlier replacements.
</p>
<p>
For example, consider the code snippet <code>s.replace(/\/\.\.\//g, "")</code>, which attempts
to strip out all occurences of <code>/../</code> from <code>s</code>. This will not work as
expected: for the string <code>/./.././</code>, for example, it will remove the single
occurrence of <code>/../</code> in the middle, but the remainder of the string then becomes
<code>/../</code>, which is another instance of the substring we were trying to remove.
</p>
</recommendation>
<example>

View File

@@ -4,7 +4,7 @@
* insertion of forged log entries by a malicious user.
* @kind path-problem
* @problem.severity error
* @security-severity 7.8
* @security-severity 6.1
* @precision medium
* @id js/log-injection
* @tags security

View File

@@ -16,9 +16,14 @@ import semmle.javascript.security.dataflow.BrokenCryptoAlgorithmQuery
import semmle.javascript.security.SensitiveActions
import DataFlow::PathGraph
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
from
Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, Source sourceNode,
Sink sinkNode
where
cfg.hasFlowPath(source, sink) and
not source.getNode() instanceof CleartextPasswordExpr // flagged by js/insufficient-password-hash
select sink.getNode(), source, sink, "A broken or weak cryptographic algorithm depends on $@.",
source.getNode(), "sensitive data from " + source.getNode().(Source).describe()
sourceNode = source.getNode() and
sinkNode = sink.getNode() and
not sourceNode instanceof CleartextPasswordExpr // flagged by js/insufficient-password-hash
select sinkNode, source, sink, "$@ depends on $@.", sinkNode.getInitialization(),
"A broken or weak cryptographic algorithm", sourceNode,
"sensitive data from " + sourceNode.describe()

View File

@@ -1 +0,0 @@
| examples/RemotePropertyInjection.js:8:8:8:11 | prop | A $@ is used as a property name to write to. | examples/RemotePropertyInjection.js:7:13:7:36 | req.que ... trolled | user-provided value |

View File

@@ -16,6 +16,10 @@ To guard against untrusted URL redirection, it is advisable to avoid putting use
directly into a redirect URL. Instead, maintain a list of authorized
redirects on the server; then choose from that list based on the user input provided.
</p>
<p>
If this is not possible, then the user input should be validated in some other way,
for example, by verifying that the target URL is on the same host as the current page.
</p>
</recommendation>
<example>
@@ -32,6 +36,21 @@ before doing the redirection:
</p>
<sample src="examples/ServerSideUrlRedirectGood.js"/>
<p>
Alternatively, we can check that the target URL does not redirect to a different host
by parsing it relative to a base URL with a known host and verifying that the host
stays the same:
</p>
<sample src="examples/ServerSideUrlRedirectGood2.js"/>
<p>
Note that as written, the above code will allow redirects to URLs on <code>example.com</code>,
which is harmless but perhaps not intended. You can substitute your own domain (if known) for
<code>example.com</code> to prevent this.
</p>
</example>
<references>

View File

@@ -1,6 +1,6 @@
const app = require("express")();
app.get('/some/path', function(req, res) {
app.get("/redirect", function (req, res) {
// BAD: a request parameter is incorporated without validation into a URL redirect
res.redirect(req.param("target"));
res.redirect(req.query["target"]);
});

View File

@@ -2,9 +2,12 @@ const app = require("express")();
const VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html";
app.get('/some/path', function(req, res) {
app.get("/redirect", function (req, res) {
// GOOD: the request parameter is validated against a known fixed string
let target = req.param("target");
if (VALID_REDIRECT === target)
let target = req.query["target"];
if (VALID_REDIRECT === target) {
res.redirect(target);
} else {
res.redirect("/");
}
});

View File

@@ -0,0 +1,22 @@
const app = require("express")();
function isLocalUrl(path) {
try {
return (
// TODO: consider substituting your own domain for example.com
new URL(path, "https://example.com").origin === "https://example.com"
);
} catch (e) {
return false;
}
}
app.get("/redirect", function (req, res) {
// GOOD: check that we don't redirect to a different host
let target = req.query["target"];
if (isLocalUrl(target)) {
res.redirect(target);
} else {
res.redirect("/");
}
});

View File

@@ -39,6 +39,8 @@ predicate isSymbolicConstant(Variable v) {
exists(VarDef vd | vd = getSingleDef(v) |
vd.(VariableDeclarator).getDeclStmt() instanceof ConstDeclStmt
or
vd.(VariableDeclarator).getDeclStmt() instanceof UsingDeclStmt
or
isConstant(vd.getSource())
)
}

View File

@@ -4,6 +4,7 @@
* @description The total number of lines of JavaScript or TypeScript code across all files checked into the repository, except in `node_modules`. This is a useful metric of the size of a database. For all files that were seen during extraction, this query counts the lines of code, excluding whitespace or comments.
* @kind metric
* @tags summary
* telemetry
*/
import javascript

View File

@@ -1,4 +0,0 @@
---
category: fix
---
* Fixed an extractor crash that would occur in rare cases when a TypeScript file contains a self-referential namespace alias.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Files larger than 10 MB are no longer be extracted or analyzed.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Imports can now be resolved in more cases, where a non-constant string expression is passed to a `require()` call.

View File

@@ -0,0 +1,3 @@
## 0.7.3
No user-facing changes.

View File

@@ -0,0 +1,10 @@
## 0.7.4
### Minor Analysis Improvements
* Files larger than 10 MB are no longer be extracted or analyzed.
* Imports can now be resolved in more cases, where a non-constant string expression is passed to a `require()` call.
### Bug Fixes
* Fixed an extractor crash that would occur in rare cases when a TypeScript file contains a self-referential namespace alias.

View File

@@ -0,0 +1,5 @@
## 0.7.5
### Bug Fixes
* Fixed an extractor crash that could occur in projects containing TypeScript files larger than 10 MB.

View File

@@ -0,0 +1,3 @@
## 0.8.0
No user-facing changes.

View File

@@ -0,0 +1,5 @@
## 0.8.1
### Minor Analysis Improvements
* Added the `AmdModuleDefinition::Range` class, making it possible to define custom aliases for the AMD `define` function.

View File

@@ -0,0 +1,5 @@
## 0.8.2
### Minor Analysis Improvements
* Added modeling for importing `express-rate-limit` using a named import.

View File

@@ -0,0 +1,6 @@
## 0.8.3
### Query Metadata Changes
* Lower the security severity of log-injection to medium.
* Increase the security severity of XSS to high.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.7.2
lastReleaseVersion: 0.8.3

View File

@@ -1,4 +0,0 @@
/** DEPRECATED: Use `semmle.javascript.Actions` instead. */
deprecated module Actions {
import semmle.javascript.Actions::Actions
}

View File

@@ -1,6 +1,6 @@
name: codeql/javascript-queries
version: 0.7.3-dev
groups:
version: 0.8.4-dev
groups:
- javascript
- queries
suites: codeql-suites

View File

@@ -0,0 +1 @@
import ApiGraphs.VerifyAssertions

View File

@@ -0,0 +1,9 @@
const tag = require("tag");
tag.string`string1
${23}` // def=moduleImport("tag").getMember("exports").getMember("string").getParameter(1)
tag.highlight`string2
${23}
morestring
${42}` // def=moduleImport("tag").getMember("exports").getMember("highlight").getParameter(2)

View File

@@ -0,0 +1,3 @@
{
"name": "tagged-template"
}

View File

@@ -0,0 +1,3 @@
test.amd.range(function() {
return { foo: 42 };
});

View File

@@ -4,6 +4,7 @@ amoModule_exports
| lib/a.js:1:1:3:3 | <toplevel> | foo | lib/a.js:2:19:2:20 | 42 |
| lib/foo.js:1:1:4:0 | <toplevel> | foo | lib/foo.js:2:10:2:11 | 23 |
| lib/nested/a.js:1:1:3:3 | <toplevel> | foo | lib/nested/a.js:2:19:2:20 | 42 |
| test_range.js:1:1:4:0 | <toplevel> | foo | test_range.js:2:19:2:20 | 42 |
| tst2.js:1:1:3:3 | <toplevel> | foo | tst2.js:2:19:2:20 | 42 |
| tst3.js:1:1:3:3 | <toplevel> | foo | tst3.js:2:43:2:44 | 42 |
| tst4.js:1:1:11:3 | <toplevel> | bar | tst4.js:9:14:9:18 | b.bar |
@@ -22,6 +23,7 @@ amdModule
| lib/a.js:1:1:3:3 | <toplevel> | lib/a.js:1:1:3:2 | define( ... 2 };\\n}) |
| lib/foo.js:1:1:4:0 | <toplevel> | lib/foo.js:1:1:3:2 | define( ... : 23\\n}) |
| lib/nested/a.js:1:1:3:3 | <toplevel> | lib/nested/a.js:1:1:3:2 | define( ... 2 };\\n}) |
| test_range.js:1:1:4:0 | <toplevel> | test_range.js:1:1:3:2 | test.am ... 2 };\\n}) |
| tst2.js:1:1:3:3 | <toplevel> | tst2.js:1:1:3:2 | define( ... 42;\\n}) |
| tst3.js:1:1:3:3 | <toplevel> | tst3.js:1:1:3:2 | define( ... 42;\\n}) |
| tst4.js:1:1:11:3 | <toplevel> | tst4.js:1:1:11:2 | define( ... };\\n}) |
@@ -48,6 +50,7 @@ amdModuleDefinition
| lib/a.js:1:1:3:2 | define( ... 2 };\\n}) | lib/a.js:1:8:3:1 | functio ... 42 };\\n} |
| lib/foo.js:1:1:3:2 | define( ... : 23\\n}) | lib/foo.js:1:8:3:1 | {\\n foo: 23\\n} |
| lib/nested/a.js:1:1:3:2 | define( ... 2 };\\n}) | lib/nested/a.js:1:8:3:1 | functio ... 42 };\\n} |
| test_range.js:1:1:3:2 | test.am ... 2 };\\n}) | test_range.js:1:16:3:1 | functio ... 42 };\\n} |
| tst2.js:1:1:3:2 | define( ... 42;\\n}) | tst2.js:1:21:3:1 | functio ... = 42;\\n} |
| tst3.js:1:1:3:2 | define( ... 42;\\n}) | tst3.js:1:8:3:1 | functio ... = 42;\\n} |
| tst4.js:1:1:11:2 | define( ... };\\n}) | tst4.js:6:11:11:1 | functio ... };\\n} |
@@ -78,6 +81,7 @@ amdModuleExportedSymbol
| lib/a.js:1:1:3:3 | <toplevel> | foo |
| lib/foo.js:1:1:4:0 | <toplevel> | foo |
| lib/nested/a.js:1:1:3:3 | <toplevel> | foo |
| test_range.js:1:1:4:0 | <toplevel> | foo |
| tst2.js:1:1:3:3 | <toplevel> | foo |
| tst3.js:1:1:3:3 | <toplevel> | foo |
| tst4.js:1:1:11:3 | <toplevel> | bar |
@@ -96,6 +100,7 @@ amdModuleExpr
| lib/a.js:1:1:3:2 | define( ... 2 };\\n}) | lib/a.js:2:12:2:22 | { foo: 42 } | lib/a.js:2:12:2:22 | { foo: 42 } |
| lib/foo.js:1:1:3:2 | define( ... : 23\\n}) | lib/foo.js:1:8:3:1 | {\\n foo: 23\\n} | lib/foo.js:1:8:3:1 | {\\n foo: 23\\n} |
| lib/nested/a.js:1:1:3:2 | define( ... 2 };\\n}) | lib/nested/a.js:2:12:2:22 | { foo: 42 } | lib/nested/a.js:2:12:2:22 | { foo: 42 } |
| test_range.js:1:1:3:2 | test.am ... 2 };\\n}) | test_range.js:2:12:2:22 | { foo: 42 } | test_range.js:2:12:2:22 | { foo: 42 } |
| tst4.js:1:1:11:2 | define( ... };\\n}) | tst4.js:7:12:10:5 | {\\n ... r\\n } | tst4.js:7:12:10:5 | {\\n ... r\\n } |
| tst5.js:1:1:6:2 | define( ... };\\n}) | tst5.js:2:12:5:5 | {\\n ... r\\n } | tst5.js:2:12:5:5 | {\\n ... r\\n } |
| tst.js:1:1:6:2 | define( ... };\\n}) | tst.js:2:12:5:5 | {\\n ... r\\n } | tst.js:2:12:5:5 | {\\n ... r\\n } |

View File

@@ -1,5 +1,9 @@
import javascript
class TestAmdModuleRange extends AmdModuleDefinition::Range {
TestAmdModuleRange() { this.getCallee().(PropAccess).getQualifiedName() = "test.amd.range" }
}
query predicate amoModule_exports(Module m, string name, DataFlow::Node exportValue) {
exportValue = m.getAnExportedValue(name)
}

View File

@@ -0,0 +1,198 @@
nodes
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
| tst.html:1:5:1:9 | [ExprStmt] using | semmle.label | [ExprStmt] using |
| tst.html:1:5:1:9 | [ExprStmt] using | semmle.order | 1 |
| tst.html:1:5:1:9 | [VarRef] using | semmle.label | [VarRef] using |
| tst.js:1:1:10:1 | [FunctionDeclStmt] functio ... } } | semmle.label | [FunctionDeclStmt] functio ... } } |
| tst.js:1:1:10:1 | [FunctionDeclStmt] functio ... } } | semmle.order | 2 |
| tst.js:1:10:1:10 | [VarDecl] g | semmle.label | [VarDecl] g |
| tst.js:1:14:10:1 | [BlockStmt] { u ... } } | semmle.label | [BlockStmt] { u ... } } |
| tst.js:2:5:2:33 | [DeclStmt] using stream = ... | semmle.label | [DeclStmt] using stream = ... |
| tst.js:2:11:2:16 | [VarDecl] stream | semmle.label | [VarDecl] stream |
| tst.js:2:11:2:32 | [VariableDeclarator] stream ... ource() | semmle.label | [VariableDeclarator] stream ... ource() |
| tst.js:2:20:2:30 | [VarRef] getResource | semmle.label | [VarRef] getResource |
| tst.js:2:20:2:32 | [CallExpr] getResource() | semmle.label | [CallExpr] getResource() |
| tst.js:4:5:4:7 | [VarRef] let | semmle.label | [VarRef] let |
| tst.js:4:5:4:19 | [CallExpr] let (test = 20) | semmle.label | [CallExpr] let (test = 20) |
| tst.js:4:5:4:20 | [ExprStmt] let (test = 20); | semmle.label | [ExprStmt] let (test = 20); |
| tst.js:4:10:4:13 | [VarRef] test | semmle.label | [VarRef] test |
| tst.js:4:10:4:18 | [AssignExpr] test = 20 | semmle.label | [AssignExpr] test = 20 |
| tst.js:4:17:4:18 | [Literal] 20 | semmle.label | [Literal] 20 |
| tst.js:6:5:9:5 | [ForStmt] for (us ... ; } | semmle.label | [ForStmt] for (us ... ; } |
| tst.js:6:10:6:38 | [DeclStmt] using stream2 = ... | semmle.label | [DeclStmt] using stream2 = ... |
| tst.js:6:16:6:22 | [VarDecl] stream2 | semmle.label | [VarDecl] stream2 |
| tst.js:6:16:6:38 | [VariableDeclarator] stream2 ... ource() | semmle.label | [VariableDeclarator] stream2 ... ource() |
| tst.js:6:26:6:36 | [VarRef] getResource | semmle.label | [VarRef] getResource |
| tst.js:6:26:6:38 | [CallExpr] getResource() | semmle.label | [CallExpr] getResource() |
| tst.js:6:45:9:5 | [BlockStmt] { ... ; } | semmle.label | [BlockStmt] { ... ; } |
| tst.js:8:9:8:14 | [BreakStmt] break; | semmle.label | [BreakStmt] break; |
| tst.js:12:1:21:1 | [FunctionDeclStmt] async f ... nd"); } | semmle.label | [FunctionDeclStmt] async f ... nd"); } |
| tst.js:12:1:21:1 | [FunctionDeclStmt] async f ... nd"); } | semmle.order | 3 |
| tst.js:12:16:12:16 | [VarDecl] h | semmle.label | [VarDecl] h |
| tst.js:12:20:21:1 | [BlockStmt] { a ... nd"); } | semmle.label | [BlockStmt] { a ... nd"); } |
| tst.js:13:5:13:39 | [DeclStmt] using stream = ... | semmle.label | [DeclStmt] using stream = ... |
| tst.js:13:17:13:22 | [VarDecl] stream | semmle.label | [VarDecl] stream |
| tst.js:13:17:13:38 | [VariableDeclarator] stream ... ource() | semmle.label | [VariableDeclarator] stream ... ource() |
| tst.js:13:26:13:36 | [VarRef] getResource | semmle.label | [VarRef] getResource |
| tst.js:13:26:13:38 | [CallExpr] getResource() | semmle.label | [CallExpr] getResource() |
| tst.js:15:5:18:5 | [ForStmt] for (aw ... ; } | semmle.label | [ForStmt] for (aw ... ; } |
| tst.js:15:16:15:44 | [DeclStmt] using stream2 = ... | semmle.label | [DeclStmt] using stream2 = ... |
| tst.js:15:22:15:28 | [VarDecl] stream2 | semmle.label | [VarDecl] stream2 |
| tst.js:15:22:15:44 | [VariableDeclarator] stream2 ... ource() | semmle.label | [VariableDeclarator] stream2 ... ource() |
| tst.js:15:32:15:42 | [VarRef] getResource | semmle.label | [VarRef] getResource |
| tst.js:15:32:15:44 | [CallExpr] getResource() | semmle.label | [CallExpr] getResource() |
| tst.js:15:51:18:5 | [BlockStmt] { ... ; } | semmle.label | [BlockStmt] { ... ; } |
| tst.js:17:9:17:14 | [BreakStmt] break; | semmle.label | [BreakStmt] break; |
| tst.js:20:5:20:11 | [VarRef] console | semmle.label | [VarRef] console |
| tst.js:20:5:20:15 | [DotExpr] console.log | semmle.label | [DotExpr] console.log |
| tst.js:20:5:20:22 | [MethodCallExpr] console.log("end") | semmle.label | [MethodCallExpr] console.log("end") |
| tst.js:20:5:20:23 | [ExprStmt] console.log("end"); | semmle.label | [ExprStmt] console.log("end"); |
| tst.js:20:13:20:15 | [Label] log | semmle.label | [Label] log |
| tst.js:20:17:20:21 | [Literal] "end" | semmle.label | [Literal] "end" |
| tst.js:23:1:29:1 | [FunctionDeclStmt] functio ... ing); } | semmle.label | [FunctionDeclStmt] functio ... ing); } |
| tst.js:23:1:29:1 | [FunctionDeclStmt] functio ... ing); } | semmle.order | 4 |
| tst.js:23:10:23:18 | [VarDecl] usesUsing | semmle.label | [VarDecl] usesUsing |
| tst.js:23:22:29:1 | [BlockStmt] { u ... ing); } | semmle.label | [BlockStmt] { u ... ing); } |
| tst.js:24:5:24:9 | [VarRef] using | semmle.label | [VarRef] using |
| tst.js:24:5:24:16 | [CallExpr] using("foo") | semmle.label | [CallExpr] using("foo") |
| tst.js:24:5:24:17 | [ExprStmt] using("foo"); | semmle.label | [ExprStmt] using("foo"); |
| tst.js:24:11:24:15 | [Literal] "foo" | semmle.label | [Literal] "foo" |
| tst.js:25:5:27:5 | [FunctionDeclStmt] functio ... . } | semmle.label | [FunctionDeclStmt] functio ... . } |
| tst.js:25:14:25:18 | [VarDecl] using | semmle.label | [VarDecl] using |
| tst.js:25:20:25:22 | [SimpleParameter] foo | semmle.label | [SimpleParameter] foo |
| tst.js:25:25:27:5 | [BlockStmt] { ... . } | semmle.label | [BlockStmt] { ... . } |
| tst.js:28:5:28:9 | [VarRef] using | semmle.label | [VarRef] using |
| tst.js:28:5:28:16 | [CallExpr] using(using) | semmle.label | [CallExpr] using(using) |
| tst.js:28:5:28:17 | [ExprStmt] using(using); | semmle.label | [ExprStmt] using(using); |
| tst.js:28:11:28:15 | [VarRef] using | semmle.label | [VarRef] using |
edges
| file://:0:0:0:0 | (Arguments) | tst.js:4:10:4:18 | [AssignExpr] test = 20 | semmle.label | 0 |
| file://:0:0:0:0 | (Arguments) | tst.js:4:10:4:18 | [AssignExpr] test = 20 | semmle.order | 0 |
| file://:0:0:0:0 | (Arguments) | tst.js:20:17:20:21 | [Literal] "end" | semmle.label | 0 |
| file://:0:0:0:0 | (Arguments) | tst.js:20:17:20:21 | [Literal] "end" | semmle.order | 0 |
| file://:0:0:0:0 | (Arguments) | tst.js:24:11:24:15 | [Literal] "foo" | semmle.label | 0 |
| file://:0:0:0:0 | (Arguments) | tst.js:24:11:24:15 | [Literal] "foo" | semmle.order | 0 |
| file://:0:0:0:0 | (Arguments) | tst.js:28:11:28:15 | [VarRef] using | semmle.label | 0 |
| file://:0:0:0:0 | (Arguments) | tst.js:28:11:28:15 | [VarRef] using | semmle.order | 0 |
| file://:0:0:0:0 | (Parameters) | tst.js:25:20:25:22 | [SimpleParameter] foo | semmle.label | 0 |
| file://:0:0:0:0 | (Parameters) | tst.js:25:20:25:22 | [SimpleParameter] foo | semmle.order | 0 |
| tst.html:1:5:1:9 | [ExprStmt] using | tst.html:1:5:1:9 | [VarRef] using | semmle.label | 1 |
| tst.html:1:5:1:9 | [ExprStmt] using | tst.html:1:5:1:9 | [VarRef] using | semmle.order | 1 |
| tst.js:1:1:10:1 | [FunctionDeclStmt] functio ... } } | tst.js:1:10:1:10 | [VarDecl] g | semmle.label | 0 |
| tst.js:1:1:10:1 | [FunctionDeclStmt] functio ... } } | tst.js:1:10:1:10 | [VarDecl] g | semmle.order | 0 |
| tst.js:1:1:10:1 | [FunctionDeclStmt] functio ... } } | tst.js:1:14:10:1 | [BlockStmt] { u ... } } | semmle.label | 5 |
| tst.js:1:1:10:1 | [FunctionDeclStmt] functio ... } } | tst.js:1:14:10:1 | [BlockStmt] { u ... } } | semmle.order | 5 |
| tst.js:1:14:10:1 | [BlockStmt] { u ... } } | tst.js:2:5:2:33 | [DeclStmt] using stream = ... | semmle.label | 1 |
| tst.js:1:14:10:1 | [BlockStmt] { u ... } } | tst.js:2:5:2:33 | [DeclStmt] using stream = ... | semmle.order | 1 |
| tst.js:1:14:10:1 | [BlockStmt] { u ... } } | tst.js:4:5:4:20 | [ExprStmt] let (test = 20); | semmle.label | 2 |
| tst.js:1:14:10:1 | [BlockStmt] { u ... } } | tst.js:4:5:4:20 | [ExprStmt] let (test = 20); | semmle.order | 2 |
| tst.js:1:14:10:1 | [BlockStmt] { u ... } } | tst.js:6:5:9:5 | [ForStmt] for (us ... ; } | semmle.label | 3 |
| tst.js:1:14:10:1 | [BlockStmt] { u ... } } | tst.js:6:5:9:5 | [ForStmt] for (us ... ; } | semmle.order | 3 |
| tst.js:2:5:2:33 | [DeclStmt] using stream = ... | tst.js:2:11:2:32 | [VariableDeclarator] stream ... ource() | semmle.label | 1 |
| tst.js:2:5:2:33 | [DeclStmt] using stream = ... | tst.js:2:11:2:32 | [VariableDeclarator] stream ... ource() | semmle.order | 1 |
| tst.js:2:11:2:32 | [VariableDeclarator] stream ... ource() | tst.js:2:11:2:16 | [VarDecl] stream | semmle.label | 1 |
| tst.js:2:11:2:32 | [VariableDeclarator] stream ... ource() | tst.js:2:11:2:16 | [VarDecl] stream | semmle.order | 1 |
| tst.js:2:11:2:32 | [VariableDeclarator] stream ... ource() | tst.js:2:20:2:32 | [CallExpr] getResource() | semmle.label | 2 |
| tst.js:2:11:2:32 | [VariableDeclarator] stream ... ource() | tst.js:2:20:2:32 | [CallExpr] getResource() | semmle.order | 2 |
| tst.js:2:20:2:32 | [CallExpr] getResource() | tst.js:2:20:2:30 | [VarRef] getResource | semmle.label | 0 |
| tst.js:2:20:2:32 | [CallExpr] getResource() | tst.js:2:20:2:30 | [VarRef] getResource | semmle.order | 0 |
| tst.js:4:5:4:19 | [CallExpr] let (test = 20) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
| tst.js:4:5:4:19 | [CallExpr] let (test = 20) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
| tst.js:4:5:4:19 | [CallExpr] let (test = 20) | tst.js:4:5:4:7 | [VarRef] let | semmle.label | 0 |
| tst.js:4:5:4:19 | [CallExpr] let (test = 20) | tst.js:4:5:4:7 | [VarRef] let | semmle.order | 0 |
| tst.js:4:5:4:20 | [ExprStmt] let (test = 20); | tst.js:4:5:4:19 | [CallExpr] let (test = 20) | semmle.label | 1 |
| tst.js:4:5:4:20 | [ExprStmt] let (test = 20); | tst.js:4:5:4:19 | [CallExpr] let (test = 20) | semmle.order | 1 |
| tst.js:4:10:4:18 | [AssignExpr] test = 20 | tst.js:4:10:4:13 | [VarRef] test | semmle.label | 1 |
| tst.js:4:10:4:18 | [AssignExpr] test = 20 | tst.js:4:10:4:13 | [VarRef] test | semmle.order | 1 |
| tst.js:4:10:4:18 | [AssignExpr] test = 20 | tst.js:4:17:4:18 | [Literal] 20 | semmle.label | 2 |
| tst.js:4:10:4:18 | [AssignExpr] test = 20 | tst.js:4:17:4:18 | [Literal] 20 | semmle.order | 2 |
| tst.js:6:5:9:5 | [ForStmt] for (us ... ; } | tst.js:6:10:6:38 | [DeclStmt] using stream2 = ... | semmle.label | 1 |
| tst.js:6:5:9:5 | [ForStmt] for (us ... ; } | tst.js:6:10:6:38 | [DeclStmt] using stream2 = ... | semmle.order | 1 |
| tst.js:6:5:9:5 | [ForStmt] for (us ... ; } | tst.js:6:45:9:5 | [BlockStmt] { ... ; } | semmle.label | 2 |
| tst.js:6:5:9:5 | [ForStmt] for (us ... ; } | tst.js:6:45:9:5 | [BlockStmt] { ... ; } | semmle.order | 2 |
| tst.js:6:10:6:38 | [DeclStmt] using stream2 = ... | tst.js:6:16:6:38 | [VariableDeclarator] stream2 ... ource() | semmle.label | 1 |
| tst.js:6:10:6:38 | [DeclStmt] using stream2 = ... | tst.js:6:16:6:38 | [VariableDeclarator] stream2 ... ource() | semmle.order | 1 |
| tst.js:6:16:6:38 | [VariableDeclarator] stream2 ... ource() | tst.js:6:16:6:22 | [VarDecl] stream2 | semmle.label | 1 |
| tst.js:6:16:6:38 | [VariableDeclarator] stream2 ... ource() | tst.js:6:16:6:22 | [VarDecl] stream2 | semmle.order | 1 |
| tst.js:6:16:6:38 | [VariableDeclarator] stream2 ... ource() | tst.js:6:26:6:38 | [CallExpr] getResource() | semmle.label | 2 |
| tst.js:6:16:6:38 | [VariableDeclarator] stream2 ... ource() | tst.js:6:26:6:38 | [CallExpr] getResource() | semmle.order | 2 |
| tst.js:6:26:6:38 | [CallExpr] getResource() | tst.js:6:26:6:36 | [VarRef] getResource | semmle.label | 0 |
| tst.js:6:26:6:38 | [CallExpr] getResource() | tst.js:6:26:6:36 | [VarRef] getResource | semmle.order | 0 |
| tst.js:6:45:9:5 | [BlockStmt] { ... ; } | tst.js:8:9:8:14 | [BreakStmt] break; | semmle.label | 1 |
| tst.js:6:45:9:5 | [BlockStmt] { ... ; } | tst.js:8:9:8:14 | [BreakStmt] break; | semmle.order | 1 |
| tst.js:12:1:21:1 | [FunctionDeclStmt] async f ... nd"); } | tst.js:12:16:12:16 | [VarDecl] h | semmle.label | 0 |
| tst.js:12:1:21:1 | [FunctionDeclStmt] async f ... nd"); } | tst.js:12:16:12:16 | [VarDecl] h | semmle.order | 0 |
| tst.js:12:1:21:1 | [FunctionDeclStmt] async f ... nd"); } | tst.js:12:20:21:1 | [BlockStmt] { a ... nd"); } | semmle.label | 5 |
| tst.js:12:1:21:1 | [FunctionDeclStmt] async f ... nd"); } | tst.js:12:20:21:1 | [BlockStmt] { a ... nd"); } | semmle.order | 5 |
| tst.js:12:20:21:1 | [BlockStmt] { a ... nd"); } | tst.js:13:5:13:39 | [DeclStmt] using stream = ... | semmle.label | 1 |
| tst.js:12:20:21:1 | [BlockStmt] { a ... nd"); } | tst.js:13:5:13:39 | [DeclStmt] using stream = ... | semmle.order | 1 |
| tst.js:12:20:21:1 | [BlockStmt] { a ... nd"); } | tst.js:15:5:18:5 | [ForStmt] for (aw ... ; } | semmle.label | 2 |
| tst.js:12:20:21:1 | [BlockStmt] { a ... nd"); } | tst.js:15:5:18:5 | [ForStmt] for (aw ... ; } | semmle.order | 2 |
| tst.js:12:20:21:1 | [BlockStmt] { a ... nd"); } | tst.js:20:5:20:23 | [ExprStmt] console.log("end"); | semmle.label | 3 |
| tst.js:12:20:21:1 | [BlockStmt] { a ... nd"); } | tst.js:20:5:20:23 | [ExprStmt] console.log("end"); | semmle.order | 3 |
| tst.js:13:5:13:39 | [DeclStmt] using stream = ... | tst.js:13:17:13:38 | [VariableDeclarator] stream ... ource() | semmle.label | 1 |
| tst.js:13:5:13:39 | [DeclStmt] using stream = ... | tst.js:13:17:13:38 | [VariableDeclarator] stream ... ource() | semmle.order | 1 |
| tst.js:13:17:13:38 | [VariableDeclarator] stream ... ource() | tst.js:13:17:13:22 | [VarDecl] stream | semmle.label | 1 |
| tst.js:13:17:13:38 | [VariableDeclarator] stream ... ource() | tst.js:13:17:13:22 | [VarDecl] stream | semmle.order | 1 |
| tst.js:13:17:13:38 | [VariableDeclarator] stream ... ource() | tst.js:13:26:13:38 | [CallExpr] getResource() | semmle.label | 2 |
| tst.js:13:17:13:38 | [VariableDeclarator] stream ... ource() | tst.js:13:26:13:38 | [CallExpr] getResource() | semmle.order | 2 |
| tst.js:13:26:13:38 | [CallExpr] getResource() | tst.js:13:26:13:36 | [VarRef] getResource | semmle.label | 0 |
| tst.js:13:26:13:38 | [CallExpr] getResource() | tst.js:13:26:13:36 | [VarRef] getResource | semmle.order | 0 |
| tst.js:15:5:18:5 | [ForStmt] for (aw ... ; } | tst.js:15:16:15:44 | [DeclStmt] using stream2 = ... | semmle.label | 1 |
| tst.js:15:5:18:5 | [ForStmt] for (aw ... ; } | tst.js:15:16:15:44 | [DeclStmt] using stream2 = ... | semmle.order | 1 |
| tst.js:15:5:18:5 | [ForStmt] for (aw ... ; } | tst.js:15:51:18:5 | [BlockStmt] { ... ; } | semmle.label | 2 |
| tst.js:15:5:18:5 | [ForStmt] for (aw ... ; } | tst.js:15:51:18:5 | [BlockStmt] { ... ; } | semmle.order | 2 |
| tst.js:15:16:15:44 | [DeclStmt] using stream2 = ... | tst.js:15:22:15:44 | [VariableDeclarator] stream2 ... ource() | semmle.label | 1 |
| tst.js:15:16:15:44 | [DeclStmt] using stream2 = ... | tst.js:15:22:15:44 | [VariableDeclarator] stream2 ... ource() | semmle.order | 1 |
| tst.js:15:22:15:44 | [VariableDeclarator] stream2 ... ource() | tst.js:15:22:15:28 | [VarDecl] stream2 | semmle.label | 1 |
| tst.js:15:22:15:44 | [VariableDeclarator] stream2 ... ource() | tst.js:15:22:15:28 | [VarDecl] stream2 | semmle.order | 1 |
| tst.js:15:22:15:44 | [VariableDeclarator] stream2 ... ource() | tst.js:15:32:15:44 | [CallExpr] getResource() | semmle.label | 2 |
| tst.js:15:22:15:44 | [VariableDeclarator] stream2 ... ource() | tst.js:15:32:15:44 | [CallExpr] getResource() | semmle.order | 2 |
| tst.js:15:32:15:44 | [CallExpr] getResource() | tst.js:15:32:15:42 | [VarRef] getResource | semmle.label | 0 |
| tst.js:15:32:15:44 | [CallExpr] getResource() | tst.js:15:32:15:42 | [VarRef] getResource | semmle.order | 0 |
| tst.js:15:51:18:5 | [BlockStmt] { ... ; } | tst.js:17:9:17:14 | [BreakStmt] break; | semmle.label | 1 |
| tst.js:15:51:18:5 | [BlockStmt] { ... ; } | tst.js:17:9:17:14 | [BreakStmt] break; | semmle.order | 1 |
| tst.js:20:5:20:15 | [DotExpr] console.log | tst.js:20:5:20:11 | [VarRef] console | semmle.label | 1 |
| tst.js:20:5:20:15 | [DotExpr] console.log | tst.js:20:5:20:11 | [VarRef] console | semmle.order | 1 |
| tst.js:20:5:20:15 | [DotExpr] console.log | tst.js:20:13:20:15 | [Label] log | semmle.label | 2 |
| tst.js:20:5:20:15 | [DotExpr] console.log | tst.js:20:13:20:15 | [Label] log | semmle.order | 2 |
| tst.js:20:5:20:22 | [MethodCallExpr] console.log("end") | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
| tst.js:20:5:20:22 | [MethodCallExpr] console.log("end") | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
| tst.js:20:5:20:22 | [MethodCallExpr] console.log("end") | tst.js:20:5:20:15 | [DotExpr] console.log | semmle.label | 0 |
| tst.js:20:5:20:22 | [MethodCallExpr] console.log("end") | tst.js:20:5:20:15 | [DotExpr] console.log | semmle.order | 0 |
| tst.js:20:5:20:23 | [ExprStmt] console.log("end"); | tst.js:20:5:20:22 | [MethodCallExpr] console.log("end") | semmle.label | 1 |
| tst.js:20:5:20:23 | [ExprStmt] console.log("end"); | tst.js:20:5:20:22 | [MethodCallExpr] console.log("end") | semmle.order | 1 |
| tst.js:23:1:29:1 | [FunctionDeclStmt] functio ... ing); } | tst.js:23:10:23:18 | [VarDecl] usesUsing | semmle.label | 0 |
| tst.js:23:1:29:1 | [FunctionDeclStmt] functio ... ing); } | tst.js:23:10:23:18 | [VarDecl] usesUsing | semmle.order | 0 |
| tst.js:23:1:29:1 | [FunctionDeclStmt] functio ... ing); } | tst.js:23:22:29:1 | [BlockStmt] { u ... ing); } | semmle.label | 5 |
| tst.js:23:1:29:1 | [FunctionDeclStmt] functio ... ing); } | tst.js:23:22:29:1 | [BlockStmt] { u ... ing); } | semmle.order | 5 |
| tst.js:23:22:29:1 | [BlockStmt] { u ... ing); } | tst.js:24:5:24:17 | [ExprStmt] using("foo"); | semmle.label | 1 |
| tst.js:23:22:29:1 | [BlockStmt] { u ... ing); } | tst.js:24:5:24:17 | [ExprStmt] using("foo"); | semmle.order | 1 |
| tst.js:23:22:29:1 | [BlockStmt] { u ... ing); } | tst.js:25:5:27:5 | [FunctionDeclStmt] functio ... . } | semmle.label | 2 |
| tst.js:23:22:29:1 | [BlockStmt] { u ... ing); } | tst.js:25:5:27:5 | [FunctionDeclStmt] functio ... . } | semmle.order | 2 |
| tst.js:23:22:29:1 | [BlockStmt] { u ... ing); } | tst.js:28:5:28:17 | [ExprStmt] using(using); | semmle.label | 3 |
| tst.js:23:22:29:1 | [BlockStmt] { u ... ing); } | tst.js:28:5:28:17 | [ExprStmt] using(using); | semmle.order | 3 |
| tst.js:24:5:24:16 | [CallExpr] using("foo") | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
| tst.js:24:5:24:16 | [CallExpr] using("foo") | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
| tst.js:24:5:24:16 | [CallExpr] using("foo") | tst.js:24:5:24:9 | [VarRef] using | semmle.label | 0 |
| tst.js:24:5:24:16 | [CallExpr] using("foo") | tst.js:24:5:24:9 | [VarRef] using | semmle.order | 0 |
| tst.js:24:5:24:17 | [ExprStmt] using("foo"); | tst.js:24:5:24:16 | [CallExpr] using("foo") | semmle.label | 1 |
| tst.js:24:5:24:17 | [ExprStmt] using("foo"); | tst.js:24:5:24:16 | [CallExpr] using("foo") | semmle.order | 1 |
| tst.js:25:5:27:5 | [FunctionDeclStmt] functio ... . } | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
| tst.js:25:5:27:5 | [FunctionDeclStmt] functio ... . } | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
| tst.js:25:5:27:5 | [FunctionDeclStmt] functio ... . } | tst.js:25:14:25:18 | [VarDecl] using | semmle.label | 0 |
| tst.js:25:5:27:5 | [FunctionDeclStmt] functio ... . } | tst.js:25:14:25:18 | [VarDecl] using | semmle.order | 0 |
| tst.js:25:5:27:5 | [FunctionDeclStmt] functio ... . } | tst.js:25:25:27:5 | [BlockStmt] { ... . } | semmle.label | 5 |
| tst.js:25:5:27:5 | [FunctionDeclStmt] functio ... . } | tst.js:25:25:27:5 | [BlockStmt] { ... . } | semmle.order | 5 |
| tst.js:28:5:28:16 | [CallExpr] using(using) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
| tst.js:28:5:28:16 | [CallExpr] using(using) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
| tst.js:28:5:28:16 | [CallExpr] using(using) | tst.js:28:5:28:9 | [VarRef] using | semmle.label | 0 |
| tst.js:28:5:28:16 | [CallExpr] using(using) | tst.js:28:5:28:9 | [VarRef] using | semmle.order | 0 |
| tst.js:28:5:28:17 | [ExprStmt] using(using); | tst.js:28:5:28:16 | [CallExpr] using(using) | semmle.label | 1 |
| tst.js:28:5:28:17 | [ExprStmt] using(using); | tst.js:28:5:28:16 | [CallExpr] using(using) | semmle.order | 1 |
graphProperties
| semmle.graphKind | tree |

View File

@@ -0,0 +1,2 @@
import javascript
import semmle.javascript.PrintAst

Some files were not shown because too many files have changed in this diff Show More