mirror of
https://github.com/github/codeql.git
synced 2026-04-25 08:45:14 +02:00
Merge branch 'main' into amammad-js-CodeInjection_execa
This commit is contained in:
11
javascript/BUILD.bazel
Normal file
11
javascript/BUILD.bazel
Normal file
@@ -0,0 +1,11 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
alias(
|
||||
name = "dbscheme",
|
||||
actual = "//javascript/ql/lib:dbscheme",
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "dbscheme-stats",
|
||||
actual = "//javascript/ql/lib:dbscheme-stats",
|
||||
)
|
||||
@@ -361,7 +361,10 @@ function handleParseCommand(command: ParseCommand, checkPending = true) {
|
||||
let filename = command.filename;
|
||||
let expectedFilename = state.pendingFiles[state.pendingFileIndex];
|
||||
if (expectedFilename !== filename && checkPending) {
|
||||
throw new Error("File requested out of order. Expected '" + expectedFilename + "' but got '" + filename + "'");
|
||||
// File was requested out of order. This happens in rare cases because the Java process decided against extracting it,
|
||||
// for example because it was too large. Just recover and accept that some work was wasted.
|
||||
state.pendingResponse = null;
|
||||
state.pendingFileIndex = state.pendingFiles.indexOf(filename);
|
||||
}
|
||||
++state.pendingFileIndex;
|
||||
let response = state.pendingResponse || extractFile(command.filename);
|
||||
|
||||
@@ -2708,7 +2708,8 @@ public class Parser {
|
||||
Matcher m = Whitespace.skipWhiteSpace.matcher(this.input);
|
||||
m.find(this.pos);
|
||||
int next = m.end();
|
||||
return !Whitespace.lineBreakG.matcher(inputSubstring(this.pos, next)).matches()
|
||||
return this.input.length() > next &&
|
||||
!Whitespace.lineBreakG.matcher(inputSubstring(this.pos, next)).matches()
|
||||
&& Identifiers.isIdentifierChar(this.input.codePointAt(next), false);
|
||||
}
|
||||
|
||||
|
||||
15
javascript/ql/lib/BUILD.bazel
Normal file
15
javascript/ql/lib/BUILD.bazel
Normal 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",
|
||||
)
|
||||
@@ -1,3 +1,13 @@
|
||||
## 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.
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* Added support for TypeScript 5.2.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* 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,0 +1,9 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* 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.
|
||||
5
javascript/ql/lib/change-notes/released/0.7.4.md
Normal file
5
javascript/ql/lib/change-notes/released/0.7.4.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 0.7.4
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* Added support for TypeScript 5.2.
|
||||
3
javascript/ql/lib/change-notes/released/0.7.5.md
Normal file
3
javascript/ql/lib/change-notes/released/0.7.5.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.7.5
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.7.3
|
||||
lastReleaseVersion: 0.7.5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/javascript-all
|
||||
version: 0.7.4-dev
|
||||
version: 0.8.0-dev
|
||||
groups: javascript
|
||||
dbscheme: semmlecode.javascript.dbscheme
|
||||
extractor: javascript
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() }
|
||||
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -118,8 +118,6 @@ module Connect {
|
||||
override string getCredentialsKind() { result = kind }
|
||||
}
|
||||
|
||||
deprecated class RequestExpr = NodeJSLib::RequestExpr;
|
||||
|
||||
class RequestNode = NodeJSLib::RequestNode;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
/** DEPRECATED. Import `semmle.javascript.security.regexp.ExponentialBackTracking` instead. */
|
||||
|
||||
deprecated private import semmle.javascript.security.regexp.ExponentialBackTracking as Dep
|
||||
import Dep
|
||||
@@ -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;
|
||||
@@ -1,4 +0,0 @@
|
||||
/** DEPRECATED. Import `semmle.javascript.security.regexp.PolynomialReDoSCustomizations` instead. */
|
||||
|
||||
deprecated private import semmle.javascript.security.regexp.PolynomialReDoSCustomizations as Dep
|
||||
import Dep
|
||||
@@ -1,4 +0,0 @@
|
||||
/** DEPRECATED. Import `semmle.javascript.security.regexp.NfaUtils` instead. */
|
||||
|
||||
deprecated private import semmle.javascript.security.regexp.NfaUtils as Dep
|
||||
import Dep
|
||||
@@ -1,4 +0,0 @@
|
||||
/** DEPRECATED. Import `semmle.javascript.security.regexp.SuperlinearBackTracking` instead. */
|
||||
|
||||
deprecated private import semmle.javascript.security.regexp.SuperlinearBackTracking as Dep
|
||||
import Dep
|
||||
@@ -1,3 +1,20 @@
|
||||
## 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.
|
||||
|
||||
@@ -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(/<!--|--!?>/g, "");
|
||||
</sample>
|
||||
|
||||
<p>
|
||||
Given the input string "<!<!--- comment --->>", the output will be "<!-- comment -->",
|
||||
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(/<!--|--!?>/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(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/g, "");
|
||||
</sample>
|
||||
|
||||
<p>
|
||||
If the input string is "<scrip<script>is removed</script>t>alert(123)</script>",
|
||||
the output will be "<script>alert(123)</script>", which still contains a script tag.
|
||||
</p>
|
||||
<p>
|
||||
A fix for this issue is to rewrite the regular expression to match single characters
|
||||
("<" and ">") 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(/<|>/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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 |
|
||||
@@ -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>
|
||||
|
||||
@@ -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"]);
|
||||
});
|
||||
|
||||
@@ -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("/");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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("/");
|
||||
}
|
||||
});
|
||||
@@ -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.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Files larger than 10 MB are no longer be extracted or analyzed.
|
||||
@@ -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.
|
||||
4
javascript/ql/src/change-notes/2023-10-05-amd-range.md
Normal file
4
javascript/ql/src/change-notes/2023-10-05-amd-range.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added the `AmdModuleDefinition::Range` class, making it possible to define custom aliases for the AMD `define` function.
|
||||
10
javascript/ql/src/change-notes/released/0.7.4.md
Normal file
10
javascript/ql/src/change-notes/released/0.7.4.md
Normal 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.
|
||||
5
javascript/ql/src/change-notes/released/0.7.5.md
Normal file
5
javascript/ql/src/change-notes/released/0.7.5.md
Normal 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.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.7.3
|
||||
lastReleaseVersion: 0.7.5
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
/** DEPRECATED: Use `semmle.javascript.Actions` instead. */
|
||||
deprecated module Actions {
|
||||
import semmle.javascript.Actions::Actions
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
name: codeql/javascript-queries
|
||||
version: 0.7.4-dev
|
||||
groups:
|
||||
version: 0.8.0-dev
|
||||
groups:
|
||||
- javascript
|
||||
- queries
|
||||
suites: codeql-suites
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import ApiGraphs.VerifyAssertions
|
||||
9
javascript/ql/test/ApiGraphs/tagged-template/index.js
Normal file
9
javascript/ql/test/ApiGraphs/tagged-template/index.js
Normal 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)
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"name": "tagged-template"
|
||||
}
|
||||
3
javascript/ql/test/library-tests/AMD/test_range.js
Normal file
3
javascript/ql/test/library-tests/AMD/test_range.js
Normal file
@@ -0,0 +1,3 @@
|
||||
test.amd.range(function() {
|
||||
return { foo: 42 };
|
||||
});
|
||||
@@ -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 } |
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -4,8 +4,11 @@ nodes
|
||||
| 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 | 1 |
|
||||
| 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 = ... |
|
||||
@@ -28,7 +31,7 @@ nodes
|
||||
| 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 | 2 |
|
||||
| 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 = ... |
|
||||
@@ -51,7 +54,7 @@ nodes
|
||||
| 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 | 3 |
|
||||
| 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 |
|
||||
@@ -77,6 +80,8 @@ edges
|
||||
| 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 |
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<%= using %>
|
||||
<!-- the above should not crash-->
|
||||
@@ -1,3 +0,0 @@
|
||||
import javascript
|
||||
|
||||
query predicate test_getACallee(DataFlow::InvokeNode c, Function res) { res = c.getACallee() }
|
||||
@@ -1,5 +0,0 @@
|
||||
import javascript
|
||||
|
||||
query predicate test_getAFunctionValue(DataFlow::Node node, DataFlow::FunctionNode res) {
|
||||
res = node.getAFunctionValue()
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import javascript
|
||||
|
||||
query predicate test_getAnArgument(DataFlow::InvokeNode invk, DataFlow::Node res) {
|
||||
res = invk.getAnArgument()
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import javascript
|
||||
|
||||
query predicate test_getArgument(DataFlow::InvokeNode invk, int i, DataFlow::Node res) {
|
||||
res = invk.getArgument(i)
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import javascript
|
||||
|
||||
query predicate test_getCalleeName(DataFlow::InvokeNode invk, string res) {
|
||||
res = invk.getCalleeName()
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import javascript
|
||||
|
||||
query predicate test_getCalleeNode(DataFlow::InvokeNode invk, DataFlow::Node res) {
|
||||
res = invk.getCalleeNode()
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import javascript
|
||||
|
||||
query predicate test_getLastArgument(DataFlow::InvokeNode invk, DataFlow::Node res) {
|
||||
res = invk.getLastArgument()
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import javascript
|
||||
|
||||
query predicate test_getNumArgument(DataFlow::InvokeNode invk, int res) {
|
||||
res = invk.getNumArgument()
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
import javascript
|
||||
|
||||
query predicate test_isImprecise(DataFlow::InvokeNode invk) { invk.isImprecise() }
|
||||
@@ -1,3 +0,0 @@
|
||||
import javascript
|
||||
|
||||
query predicate test_isIncomplete(DataFlow::InvokeNode invk) { invk.isIncomplete() }
|
||||
@@ -1,3 +0,0 @@
|
||||
import javascript
|
||||
|
||||
query predicate test_isUncertain(DataFlow::InvokeNode invk) { invk.isUncertain() }
|
||||
@@ -0,0 +1,5 @@
|
||||
function fooTag(strings, par1, par2) {
|
||||
|
||||
}
|
||||
|
||||
fooTag`hello ${arg1} world ${arg2}`
|
||||
@@ -126,6 +126,8 @@ test_getAFunctionValue
|
||||
| strict.js:1:1:8:2 | (functi ... ode.\\n}) | strict.js:1:2:8:1 | functio ... mode.\\n} |
|
||||
| strict.js:1:2:8:1 | functio ... mode.\\n} | strict.js:1:2:8:1 | functio ... mode.\\n} |
|
||||
| strict.js:3:5:5:5 | functio ... ;\\n } | strict.js:3:5:5:5 | functio ... ;\\n } |
|
||||
| taggedTemplate.js:1:1:3:1 | functio ... 2) {\\n\\n} | taggedTemplate.js:1:1:3:1 | functio ... 2) {\\n\\n} |
|
||||
| taggedTemplate.js:5:1:5:6 | fooTag | taggedTemplate.js:1:1:3:1 | functio ... 2) {\\n\\n} |
|
||||
| tst3.js:1:1:1:22 | functio ... fn() {} | tst3.js:1:1:1:22 | functio ... fn() {} |
|
||||
| tst3.js:2:1:2:23 | functio ... n2() {} | tst3.js:2:1:2:23 | functio ... n2() {} |
|
||||
| tst.js:1:1:1:15 | function f() {} | tst.js:1:1:1:15 | function f() {} |
|
||||
@@ -221,6 +223,8 @@ test_getArgument
|
||||
| reflection.js:7:1:7:22 | reflective call | 1 | reflection.js:7:20:7:21 | 19 |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | 0 | reflection.js:8:11:8:14 | null |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | 1 | reflection.js:8:17:8:24 | [23, 19] |
|
||||
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | 1 | taggedTemplate.js:5:16:5:19 | arg1 |
|
||||
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | 2 | taggedTemplate.js:5:30:5:33 | arg2 |
|
||||
| tst.js:22:1:22:4 | l(k) | 0 | tst.js:22:3:22:3 | k |
|
||||
| tst.js:42:2:42:29 | functio ... x; }(o) | 0 | tst.js:42:28:42:28 | o |
|
||||
test_getNumArgument
|
||||
@@ -259,6 +263,7 @@ test_getNumArgument
|
||||
| strict2.js:9:10:9:14 | foo() | 0 |
|
||||
| strict.js:1:1:8:4 | (functi ... e.\\n})() | 0 |
|
||||
| strict.js:7:10:7:14 | foo() | 0 |
|
||||
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | 3 |
|
||||
| tst.js:6:1:6:3 | f() | 0 |
|
||||
| tst.js:7:1:7:3 | g() | 0 |
|
||||
| tst.js:8:1:8:3 | h() | 0 |
|
||||
@@ -362,6 +367,7 @@ test_getCalleeNode
|
||||
| strict2.js:9:10:9:14 | foo() | strict2.js:9:10:9:12 | foo |
|
||||
| strict.js:1:1:8:4 | (functi ... e.\\n})() | strict.js:1:1:8:2 | (functi ... ode.\\n}) |
|
||||
| strict.js:7:10:7:14 | foo() | strict.js:7:10:7:12 | foo |
|
||||
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | taggedTemplate.js:5:1:5:6 | fooTag |
|
||||
| tst.js:6:1:6:3 | f() | tst.js:6:1:6:1 | f |
|
||||
| tst.js:7:1:7:3 | g() | tst.js:7:1:7:1 | g |
|
||||
| tst.js:8:1:8:3 | h() | tst.js:8:1:8:1 | h |
|
||||
@@ -400,6 +406,7 @@ test_getLastArgument
|
||||
| reflection.js:7:1:7:22 | add.cal ... 23, 19) | reflection.js:7:20:7:21 | 19 |
|
||||
| reflection.js:7:1:7:22 | reflective call | reflection.js:7:20:7:21 | 19 |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | reflection.js:8:17:8:24 | [23, 19] |
|
||||
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | taggedTemplate.js:5:30:5:33 | arg2 |
|
||||
| tst.js:22:1:22:4 | l(k) | tst.js:22:3:22:3 | k |
|
||||
| tst.js:42:2:42:29 | functio ... x; }(o) | tst.js:42:28:42:28 | o |
|
||||
test_getAnArgument
|
||||
@@ -420,6 +427,8 @@ test_getAnArgument
|
||||
| reflection.js:7:1:7:22 | reflective call | reflection.js:7:20:7:21 | 19 |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | reflection.js:8:11:8:14 | null |
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | reflection.js:8:17:8:24 | [23, 19] |
|
||||
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | taggedTemplate.js:5:16:5:19 | arg1 |
|
||||
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | taggedTemplate.js:5:30:5:33 | arg2 |
|
||||
| tst.js:22:1:22:4 | l(k) | tst.js:22:3:22:3 | k |
|
||||
| tst.js:42:2:42:29 | functio ... x; }(o) | tst.js:42:28:42:28 | o |
|
||||
test_getACallee
|
||||
@@ -449,6 +458,7 @@ test_getACallee
|
||||
| reflection.js:8:1:8:25 | reflective call | reflection.js:1:1:3:1 | functio ... x+y;\\n} |
|
||||
| strict2.js:2:1:10:4 | (functi ... e.\\n})() | strict2.js:2:2:10:1 | functio ... mode.\\n} |
|
||||
| strict.js:1:1:8:4 | (functi ... e.\\n})() | strict.js:1:2:8:1 | functio ... mode.\\n} |
|
||||
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | taggedTemplate.js:1:1:3:1 | functio ... 2) {\\n\\n} |
|
||||
| tst.js:6:1:6:3 | f() | tst.js:1:1:1:15 | function f() {} |
|
||||
| tst.js:7:1:7:3 | g() | tst.js:2:9:2:21 | function() {} |
|
||||
| tst.js:8:1:8:3 | h() | tst.js:3:5:3:17 | function() {} |
|
||||
@@ -509,6 +519,7 @@ test_getCalleeName
|
||||
| reflection.js:8:1:8:25 | add.app ... 3, 19]) | apply |
|
||||
| strict2.js:9:10:9:14 | foo() | foo |
|
||||
| strict.js:7:10:7:14 | foo() | foo |
|
||||
| taggedTemplate.js:5:1:5:35 | fooTag` ... {arg2}` | fooTag |
|
||||
| tst.js:6:1:6:3 | f() | f |
|
||||
| tst.js:7:1:7:3 | g() | g |
|
||||
| tst.js:8:1:8:3 | h() | h |
|
||||
|
||||
@@ -1,11 +1,37 @@
|
||||
import isUncertain
|
||||
import getAFunctionValue
|
||||
import getArgument
|
||||
import getNumArgument
|
||||
import isIncomplete
|
||||
import getCalleeNode
|
||||
import getLastArgument
|
||||
import getAnArgument
|
||||
import getACallee
|
||||
import getCalleeName
|
||||
import isImprecise
|
||||
import javascript
|
||||
|
||||
query predicate test_isUncertain(DataFlow::InvokeNode invk) { invk.isUncertain() }
|
||||
|
||||
query predicate test_getAFunctionValue(DataFlow::Node node, DataFlow::FunctionNode res) {
|
||||
res = node.getAFunctionValue()
|
||||
}
|
||||
|
||||
query predicate test_getArgument(DataFlow::InvokeNode invk, int i, DataFlow::Node res) {
|
||||
res = invk.getArgument(i)
|
||||
}
|
||||
|
||||
query predicate test_getNumArgument(DataFlow::InvokeNode invk, int res) {
|
||||
res = invk.getNumArgument()
|
||||
}
|
||||
|
||||
query predicate test_isIncomplete(DataFlow::InvokeNode invk) { invk.isIncomplete() }
|
||||
|
||||
query predicate test_getCalleeNode(DataFlow::InvokeNode invk, DataFlow::Node res) {
|
||||
res = invk.getCalleeNode()
|
||||
}
|
||||
|
||||
query predicate test_getLastArgument(DataFlow::InvokeNode invk, DataFlow::Node res) {
|
||||
res = invk.getLastArgument()
|
||||
}
|
||||
|
||||
query predicate test_getAnArgument(DataFlow::InvokeNode invk, DataFlow::Node res) {
|
||||
res = invk.getAnArgument()
|
||||
}
|
||||
|
||||
query predicate test_getACallee(DataFlow::InvokeNode c, Function res) { res = c.getACallee() }
|
||||
|
||||
query predicate test_getCalleeName(DataFlow::InvokeNode invk, string res) {
|
||||
res = invk.getCalleeName()
|
||||
}
|
||||
|
||||
query predicate test_isImprecise(DataFlow::InvokeNode invk) { invk.isImprecise() }
|
||||
|
||||
@@ -231,6 +231,7 @@ typeInferenceMismatch
|
||||
| tst.js:2:13:2:20 | source() | tst.js:47:10:47:30 | Buffer. ... 'hex') |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:48:10:48:22 | new Buffer(x) |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:51:10:51:31 | seriali ... ript(x) |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:54:14:54:19 | unsafe |
|
||||
| xml.js:5:18:5:25 | source() | xml.js:8:14:8:17 | text |
|
||||
| xml.js:12:17:12:24 | source() | xml.js:13:14:13:19 | result |
|
||||
| xml.js:23:18:23:25 | source() | xml.js:20:14:20:17 | attr |
|
||||
|
||||
@@ -109,3 +109,4 @@
|
||||
| thisAssignments.js:4:17:4:24 | source() | thisAssignments.js:5:10:5:18 | obj.field |
|
||||
| thisAssignments.js:7:19:7:26 | source() | thisAssignments.js:8:10:8:20 | this.field2 |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:4:10:4:10 | x |
|
||||
| tst.js:2:13:2:20 | source() | tst.js:54:14:54:19 | unsafe |
|
||||
|
||||
@@ -49,4 +49,12 @@ function test() {
|
||||
|
||||
const serializeJavaScript = require("serialize-javascript");
|
||||
sink(serializeJavaScript(x)) // NOT OK
|
||||
|
||||
function tagged(strings, safe, unsafe) {
|
||||
sink(unsafe) // NOT OK
|
||||
sink(safe) // OK
|
||||
sink(strings) // OK
|
||||
}
|
||||
|
||||
tagged`foo ${"safe"} bar ${x} baz`;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
nodes
|
||||
| ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] |
|
||||
| ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] |
|
||||
| ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] |
|
||||
| express.js:7:16:7:34 | req.param("target") |
|
||||
| express.js:7:16:7:34 | req.param("target") |
|
||||
| express.js:7:16:7:34 | req.param("target") |
|
||||
@@ -114,6 +117,7 @@ nodes
|
||||
| react-native.js:9:26:9:32 | tainted |
|
||||
| react-native.js:9:26:9:32 | tainted |
|
||||
edges
|
||||
| ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] |
|
||||
| express.js:7:16:7:34 | req.param("target") | express.js:7:16:7:34 | req.param("target") |
|
||||
| express.js:12:26:12:44 | req.param("target") | express.js:12:26:12:44 | req.param("target") |
|
||||
| express.js:27:7:27:34 | target | express.js:33:18:33:23 | target |
|
||||
@@ -211,6 +215,7 @@ edges
|
||||
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
|
||||
| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted |
|
||||
#select
|
||||
| ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | Untrusted URL redirection depends on a $@. | ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | user-provided value |
|
||||
| express.js:7:16:7:34 | req.param("target") | express.js:7:16:7:34 | req.param("target") | express.js:7:16:7:34 | req.param("target") | Untrusted URL redirection depends on a $@. | express.js:7:16:7:34 | req.param("target") | user-provided value |
|
||||
| express.js:12:26:12:44 | req.param("target") | express.js:12:26:12:44 | req.param("target") | express.js:12:26:12:44 | req.param("target") | Untrusted URL redirection depends on a $@. | express.js:12:26:12:44 | req.param("target") | user-provided value |
|
||||
| express.js:33:18:33:23 | target | express.js:27:16:27:34 | req.param("target") | express.js:33:18:33:23 | target | Untrusted URL redirection depends on a $@. | express.js:27:16:27:34 | req.param("target") | user-provided value |
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
const app = require("express")();
|
||||
|
||||
app.get("/redirect", function (req, res) {
|
||||
// BAD: a request parameter is incorporated without validation into a URL redirect
|
||||
res.redirect(req.query["target"]);
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
const app = require("express")();
|
||||
|
||||
const VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html";
|
||||
|
||||
app.get("/redirect", function (req, res) {
|
||||
// GOOD: the request parameter is validated against a known fixed string
|
||||
let target = req.query["target"];
|
||||
if (VALID_REDIRECT === target) {
|
||||
res.redirect(target);
|
||||
} else {
|
||||
res.redirect("/");
|
||||
}
|
||||
});
|
||||
@@ -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("/");
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user