Merge branch 'main' into param2

This commit is contained in:
Erik Krogh Kristensen
2022-07-12 23:21:11 +02:00
1424 changed files with 88659 additions and 55939 deletions

View File

@@ -0,0 +1,11 @@
class AstNodeWithSymbol extends @ast_node_with_symbol {
string toString() { none() }
}
class Symbol extends @symbol {
string toString() { none() }
}
from AstNodeWithSymbol node, Symbol symbol
where ast_node_symbol(node, symbol) and not node instanceof @external_module_declaration
select node, symbol

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
description: Associate symbols with external module declarations
compatibility: backwards
ast_node_symbol.rel: run ast_node_symbol.qlo

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
name: codeql/javascript-downgrades
groups: javascript
downgrades: .
library: true

View File

@@ -1696,4 +1696,3 @@ module.exports.R_OK = fs.R_OK;
module.exports.W_OK = fs.W_OK;
module.exports.X_OK = fs.X_OK;

View File

@@ -1068,6 +1068,7 @@ export class TypeTable {
let superType = this.typeChecker.getTypeFromTypeNode(typeExpr);
if (superType == null) continue;
let baseTypeSymbol = superType.symbol;
baseTypeSymbol = (baseTypeSymbol as any)?.type?.symbol ?? baseTypeSymbol;
if (baseTypeSymbol == null) continue;
let baseId = this.getSymbolId(baseTypeSymbol);
// Note: take care not to perform a recursive call between the two `push` calls.

View File

@@ -2191,6 +2191,7 @@ public class ASTExtractor {
visitAll(nd.getBody(), key);
contextManager.leaveContainer();
scopeManager.leaveScope();
emitNodeSymbol(nd, key);
return key;
}

View File

@@ -217,9 +217,6 @@ public class FileExtractor {
}
private boolean hasBadFileHeader(File f, String lcExt, ExtractorConfig config) {
if (!".ts".equals(lcExt)) {
return false;
}
try (FileInputStream fis = new FileInputStream(f)) {
byte[] bytes = new byte[fileHeaderSize];
int length = fis.read(bytes);

View File

@@ -43,7 +43,7 @@ public class Main {
* A version identifier that should be updated every time the extractor changes in such a way that
* it may produce different tuples for the same file under the same {@link ExtractorConfig}.
*/
public static final String EXTRACTOR_VERSION = "2022-05-24";
public static final String EXTRACTOR_VERSION = "2022-06-27";
public static final Pattern NEWLINE = Pattern.compile("\n");
@@ -153,7 +153,7 @@ public class Main {
ensureFileIsExtracted(file, ap);
}
}
TypeScriptParser tsParser = extractorState.getTypeScriptParser();
tsParser.setTypescriptRam(extractorConfig.getTypeScriptRam());
if (containsTypeScriptFiles()) {
@@ -460,7 +460,7 @@ public class Main {
if (ap.has(P_TYPESCRIPT)) return TypeScriptMode.BASIC;
return TypeScriptMode.NONE;
}
private Path inferSourceRoot(ArgsParser ap) {
List<File> files = getFilesArg(ap);
Path sourceRoot = files.iterator().next().toPath().toAbsolutePath().getParent();

View File

@@ -7,9 +7,10 @@ import com.semmle.js.ast.Visitor;
import java.util.List;
/** A statement of form <code>declare module "X" {...}</code>. */
public class ExternalModuleDeclaration extends Statement {
public class ExternalModuleDeclaration extends Statement implements INodeWithSymbol {
private final Literal name;
private final List<Statement> body;
private int symbol = -1;
public ExternalModuleDeclaration(SourceLocation loc, Literal name, List<Statement> body) {
super("ExternalModuleDeclaration", loc);
@@ -29,4 +30,14 @@ public class ExternalModuleDeclaration extends Statement {
public List<Statement> getBody() {
return body;
}
@Override
public int getSymbol() {
return this.symbol;
}
@Override
public void setSymbol(int symbol) {
this.symbol = symbol;
}
}

View File

@@ -591,7 +591,7 @@ public class TypeScriptASTConverter {
return convertTryStatement(node, loc);
case "TupleType":
return convertTupleType(node, loc);
case "NamedTupleMember":
case "NamedTupleMember":
return convertNamedTupleMember(node, loc);
case "TypeAliasDeclaration":
return convertTypeAliasDeclaration(node, loc);
@@ -1710,7 +1710,9 @@ public class TypeScriptASTConverter {
}
if (nameNode instanceof Literal) {
// Declaration of form: declare module "X" {...}
return new ExternalModuleDeclaration(loc, (Literal) nameNode, body);
ExternalModuleDeclaration decl = new ExternalModuleDeclaration(loc, (Literal) nameNode, body);
attachSymbolInformation(decl, node);
return decl;
}
if (hasFlag(node, "GlobalAugmentation")) {
// Declaration of form: declare global {...}

View File

@@ -1,3 +1,15 @@
## 0.2.0
### Major Analysis Improvements
* Added support for TypeScript 4.7.
### Minor Analysis Improvements
* All new ECMAScript 2022 features are now supported.
## 0.1.4
## 0.1.3
### Minor Analysis Improvements

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* All new ECMAScript 2022 features are now supported.

View File

@@ -1,4 +0,0 @@
---
category: majorAnalysis
---
* Added support for TypeScript 4.7.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `gray-matter` library is now modeled as a sink for the `js/code-injection` query.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Improved modeling of sensitive data sources, so common words like `certain` and `secretary` are no longer considered a certificate and a secret (respectively).

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `chownr` library is now modeled as a sink for the `js/path-injection` query.

View File

@@ -0,0 +1 @@
## 0.1.4

View File

@@ -0,0 +1,9 @@
## 0.2.0
### Major Analysis Improvements
* Added support for TypeScript 4.7.
### Minor Analysis Improvements
* All new ECMAScript 2022 features are now supported.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.1.3
lastReleaseVersion: 0.2.0

View File

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

View File

@@ -180,6 +180,35 @@ class PackageJson extends JsonObject {
Module getMainModule() {
result = min(Module m, int prio | m.getFile() = resolveMainModule(this, prio) | m order by prio)
}
/**
* Gets the `types` or `typings` field of this package.
*/
string getTypings() { result = this.getPropStringValue(["types", "typings"]) }
/**
* Gets the file containing the typings of this package, which can either be from the `types` or
* `typings` field, or derived from the `main` or `module` fields.
*/
File getTypingsFile() {
result =
TypingsModulePathString::of(this).resolve(this.getFile().getParentContainer()).getContainer()
or
not exists(TypingsModulePathString::of(this)) and
exists(File mainFile |
mainFile = this.getMainModule().getFile() and
result =
mainFile
.getParentContainer()
.getFile(mainFile.getStem().regexpReplaceAll("\\.d$", "") + ".d.ts")
)
}
/**
* Gets the module containing the typings of this package, which can either be from the `types` or
* `typings` field, or derived from the `main` or `module` fields.
*/
Module getTypingsModule() { result.getFile() = this.getTypingsFile() }
}
/** DEPRECATED: Alias for PackageJson */

View File

@@ -198,3 +198,29 @@ private class FilesPath extends PathExpr, @json_string {
private module FilesPath {
FilesPath of(PackageJson pkg) { result.getPackageJson() = pkg }
}
/**
* A JSON string in a `package.json` file specifying the path of the
* TypeScript typings entry point.
*/
class TypingsModulePathString extends PathString {
PackageJson pkg;
TypingsModulePathString() {
this = pkg.getTypings()
or
not exists(pkg.getTypings()) and
this = pkg.getMain().regexpReplaceAll("\\.[mc]?js$", ".d.ts")
}
/** Gets the `package.json` file containing this path. */
PackageJson getPackageJson() { result = pkg }
override Folder getARootFolder() { result = pkg.getFile().getParentContainer() }
}
/** Companion module to the `TypingsModulePathString` class. */
module TypingsModulePathString {
/** Get the typings path for the given `package.json` file. */
TypingsModulePathString of(PackageJson pkg) { result.getPackageJson() = pkg }
}

View File

@@ -189,6 +189,13 @@ module Promises {
* Gets the pseudo-field used to describe rejected values in a promise.
*/
string errorProp() { result = "$PromiseRejectField$" }
/** A property set containing the pseudo-properites of a promise object. */
class PromiseProps extends DataFlow::PropertySet {
PromiseProps() { this = "PromiseProps" }
override string getAProperty() { result = [valueProp(), errorProp()] }
}
}
/**
@@ -274,6 +281,24 @@ private class PromiseStep extends PreCallGraphStep {
}
}
/**
* A step from `p -> await p` for the case where `p` is not a promise.
*
* In this case, `await p` just returns `p` itself. We block flow of the promise-related
* pseudo properties through this edge.
*/
private class RawAwaitStep extends DataFlow::SharedTypeTrackingStep {
override predicate withoutPropStep(
DataFlow::Node pred, DataFlow::Node succ, DataFlow::PropertySet props
) {
exists(AwaitExpr await |
pred = await.getOperand().flow() and
succ = await.flow() and
props instanceof Promises::PromiseProps
)
}
}
/**
* This module defines how data-flow propagates into and out of a Promise.
* The data-flow is based on pseudo-properties rather than tainting the Promise object (which is what `PromiseTaintStep` does).

View File

@@ -1126,6 +1126,19 @@ module TaintTracking {
)
}
/** A test for the value of `typeof x`, restricting the potential types of `x`. */
predicate isStringTypeGuard(EqualityTest test, Expr operand, boolean polarity) {
exists(TypeofTag tag | TaintTracking::isTypeofGuard(test, operand, tag) |
// typeof x === "string" sanitizes `x` when it evaluates to false
tag = "string" and
polarity = test.getPolarity().booleanNot()
or
// typeof x === "object" sanitizes `x` when it evaluates to true
tag != "string" and
polarity = test.getPolarity()
)
}
/** Holds if `guard` is a test that checks if `operand` is a number. */
predicate isNumberGuard(DataFlow::Node guard, Expr operand, boolean polarity) {
exists(DataFlow::CallNode isNaN |

View File

@@ -70,6 +70,12 @@ class TypeTracker extends TTypeTracker {
step = LoadStep(prop) and result = MkTypeTracker(hasCall, "")
or
exists(string p | step = StoreStep(p) and prop = "" and result = MkTypeTracker(hasCall, p))
or
exists(PropertySet props |
step = WithoutPropStep(props) and
not prop = props.getAProperty() and
result = this
)
}
/** Gets a textual representation of this summary. */
@@ -373,6 +379,26 @@ class SharedTypeTrackingStep extends Unit {
) {
none()
}
/**
* Holds if type-tracking should step from `pred` to `succ` but block flow of `props` through here.
*
* This can be seen as taking a copy of the value in `pred` but without the properties in `props`.
*/
predicate withoutPropStep(DataFlow::Node pred, DataFlow::Node succ, PropertySet props) { none() }
}
/**
* A representative for a set of property names.
*
* Currently this is used to denote a set of properties in `withoutPropStep`.
*/
abstract class PropertySet extends string {
bindingset[this]
PropertySet() { any() }
/** Gets a property contained in this property set. */
abstract string getAProperty();
}
/** Provides access to the steps contributed by subclasses of `SharedTypeTrackingStep`. */
@@ -413,6 +439,15 @@ module SharedTypeTrackingStep {
) {
any(SharedTypeTrackingStep s).loadStoreStep(pred, succ, loadProp, storeProp)
}
/**
* Holds if type-tracking should step from `pred` to `succ` but block flow of `prop` through here.
*
* This can be seen as taking a copy of the value in `pred` but without the properties in `props`.
*/
predicate withoutPropStep(DataFlow::Node pred, DataFlow::Node succ, PropertySet props) {
any(SharedTypeTrackingStep s).withoutPropStep(pred, succ, props)
}
}
/**

View File

@@ -45,7 +45,8 @@ private module Cached {
CopyStep(PropertyName prop) or
LoadStoreStep(PropertyName fromProp, PropertyName toProp) {
SharedTypeTrackingStep::loadStoreStep(_, _, fromProp, toProp)
}
} or
WithoutPropStep(PropertySet props) { SharedTypeTrackingStep::withoutPropStep(_, _, props) }
}
/**
@@ -110,6 +111,11 @@ private module Cached {
summary = CopyStep(prop)
)
or
exists(PropertySet props |
SharedTypeTrackingStep::withoutPropStep(pred, succ, props) and
summary = WithoutPropStep(props)
)
or
exists(string fromProp, string toProp |
SharedTypeTrackingStep::loadStoreStep(pred, succ, fromProp, toProp) and
summary = LoadStoreStep(fromProp, toProp)
@@ -194,6 +200,8 @@ class StepSummary extends TStepSummary {
or
exists(string prop | this = CopyStep(prop) | result = "copy " + prop)
or
exists(string prop | this = WithoutPropStep(prop) | result = "without " + prop)
or
exists(string fromProp, string toProp | this = LoadStoreStep(fromProp, toProp) |
result = "load " + fromProp + " and store to " + toProp
)

View File

@@ -192,6 +192,18 @@ private class WriteFileAtomic extends FileSystemWriteAccess, DataFlow::CallNode
override DataFlow::Node getADataNode() { result = this.getArgument(1) }
}
/**
* A call to the library `chownr`.
* The library changes the owner of a file or directory recursively.
*/
private class Chownr extends FileSystemWriteAccess, DataFlow::CallNode {
Chownr() { this = DataFlow::moduleImport("chownr").getACall() }
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
override DataFlow::Node getADataNode() { none() }
}
/**
* A call to the library `recursive-readdir`.
*/

View File

@@ -17,3 +17,15 @@ private class HeuristicStringManipulationTaintStep extends TaintTracking::Shared
)
}
}
/** Any call to a library component where we assume taint from any argument to the result */
private class HeuristicLibraryCallTaintStep extends TaintTracking::SharedTaintStep {
override predicate heuristicStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(API::CallNode call |
pred = call.getAnArgument() or // the plain argument
pred = call.getAnArgument().(DataFlow::SourceNode).getAPropertyWrite().getRhs() // one property down
|
succ = call
)
}
}

View File

@@ -106,6 +106,10 @@ module ClientSideUrlRedirect {
) and
xss = true
or
// A call to `navigation.navigate`
this = DataFlow::globalVarRef("navigation").getAMethodCall("navigate").getArgument(0) and
xss = true
or
// An assignment to `location`
exists(Assignment assgn | isLocation(assgn.getTarget()) and astNode = assgn.getRhs()) and
xss = true

View File

@@ -51,6 +51,18 @@ module CodeInjection {
}
}
/** An expression parsed by the `gray-matter` library. */
class GrayMatterSink extends Sink {
GrayMatterSink() {
exists(API::CallNode call |
call = DataFlow::moduleImport("gray-matter").getACall() and
this = call.getArgument(0) and
// if the js/javascript engine is set, then we assume they are set to something safe.
not exists(call.getParameter(1).getMember("engines").getMember(["js", "javascript"]))
)
}
}
/**
* A template tag occurring in JS code, viewed as a code injection sink.
*/

View File

@@ -34,7 +34,7 @@ module UnsafeHtmlConstruction {
* A jQuery plugin options object, seen as a source for unsafe HTML constructed from input.
*/
class JQueryPluginOptionsAsSource extends Source {
JQueryPluginOptionsAsSource() { this instanceof UnsafeJQueryPlugin::JQueryPluginOptions }
JQueryPluginOptionsAsSource() { this = any(JQuery::JQueryPluginMethod meth).getAParameter() }
}
/**
@@ -180,4 +180,18 @@ module UnsafeHtmlConstruction {
override string describe() { result = "Markdown rendering" }
}
/** A test for the value of `typeof x`, restricting the potential types of `x`. */
class TypeTestGuard extends TaintTracking::SanitizerGuardNode, DataFlow::ValueNode {
override EqualityTest astNode;
Expr operand;
boolean polarity;
TypeTestGuard() { TaintTracking::isStringTypeGuard(astNode, operand, polarity) }
override predicate sanitizes(boolean outcome, Expr e) {
polarity = outcome and
e = operand
}
}
}

View File

@@ -4,7 +4,6 @@
*/
import javascript
private import semmle.javascript.dataflow.InferredTypes
private import XssThroughDomCustomizations::XssThroughDom
private import semmle.javascript.security.dataflow.DomBasedXssCustomizations
private import semmle.javascript.security.dataflow.UnsafeJQueryPluginCustomizations::UnsafeJQueryPlugin as UnsafeJQuery
@@ -52,27 +51,13 @@ class Configuration extends TaintTracking::Configuration {
}
}
/**
* A test of form `typeof x === "something"`, preventing `x` from being a string in some cases.
*
* This sanitizer helps prune infeasible paths in type-overloaded functions.
*/
/** A test for the value of `typeof x`, restricting the potential types of `x`. */
class TypeTestGuard extends TaintTracking::SanitizerGuardNode, DataFlow::ValueNode {
override EqualityTest astNode;
Expr operand;
boolean polarity;
TypeTestGuard() {
exists(TypeofTag tag | TaintTracking::isTypeofGuard(astNode, operand, tag) |
// typeof x === "string" sanitizes `x` when it evaluates to false
tag = "string" and
polarity = astNode.getPolarity().booleanNot()
or
// typeof x === "object" sanitizes `x` when it evaluates to true
tag != "string" and
polarity = astNode.getPolarity()
)
}
TypeTestGuard() { TaintTracking::isStringTypeGuard(astNode, operand, polarity) }
override predicate sanitizes(boolean outcome, Expr e) {
polarity = outcome and

View File

@@ -50,7 +50,7 @@ module HeuristicNames {
* Gets a regular expression that identifies strings that may indicate the presence of secret
* or trusted data.
*/
string maybeSecret() { result = "(?is).*((?<!is)secret|(?<!un|is)trusted).*" }
string maybeSecret() { result = "(?is).*((?<!is|is_)secret|(?<!un|un_|is|is_)trusted).*" }
/**
* Gets a regular expression that identifies strings that may indicate the presence of
@@ -96,10 +96,14 @@ module HeuristicNames {
* Gets a regular expression that identifies strings that may indicate the presence of data
* that is hashed or encrypted, and hence rendered non-sensitive, or contains special characters
* suggesting nouns within the string do not represent the meaning of the whole string (e.g. a URL or a SQL query).
*
* We also filter out common words like `certain` and `concert`, since otherwise these could
* be matched by the certificate regular expressions. Same for `accountable` (account), or
* `secretarial` (secret).
*/
string notSensitiveRegexp() {
result =
"(?is).*([^\\w$.-]|redact|censor|obfuscate|hash|md5|sha|random|((?<!un)(en))?(crypt|code)).*"
"(?is).*([^\\w$.-]|redact|censor|obfuscate|hash|md5|sha|random|((?<!un)(en))?(crypt|code)|certain|concert|secretar|accountant|accountab).*"
}
/**

View File

@@ -3,7 +3,7 @@
/** Files and folders **/
@location = @location_default;
locations_default(unique int id: @location_default,
int file: @file ref,
int beginLine: int ref,
@@ -11,25 +11,25 @@ locations_default(unique int id: @location_default,
int endLine: int ref,
int endColumn: int ref
);
@sourceline = @locatable;
numlines(int element_id: @sourceline ref,
int num_lines: int ref,
int num_code: int ref,
int num_comment: int ref
);
files(unique int id: @file,
varchar(900) name: string ref);
folders(unique int id: @folder,
varchar(900) name: string ref);
@container = @folder | @file ;
containerparent(int parent: @container ref,
unique int child: @container ref);
@@ -39,14 +39,14 @@ duplicateCode(
unique int id : @duplication,
varchar(900) relativePath : string ref,
int equivClass : int ref);
similarCode(
unique int id : @similarity,
varchar(900) relativePath : string ref,
int equivClass : int ref);
@duplication_or_similarity = @duplication | @similarity;
tokens(
int id : @duplication_or_similarity ref,
int offset : int ref,
@@ -63,9 +63,9 @@ externalData(
int column: int ref,
varchar(900) value : string ref
);
snapshotDate(unique date snapshotDate : date ref);
sourceLocationPrefix(varchar(900) prefix : string ref);
/** Version control data **/
@@ -77,18 +77,18 @@ svnentries(
date revisionDate : date ref,
int changeSize : int ref
);
svnaffectedfiles(
int id : @svnentry ref,
int file : @file ref,
varchar(500) action : string ref
);
svnentrymsg(
int id : @svnentry ref,
varchar(500) message : string ref
);
svnchurn(
int commit : @svnentry ref,
int file : @file ref,
@@ -134,15 +134,15 @@ xml_element_parent_expression(
// statements
#keyset[parent, idx]
stmts (unique int id: @stmt,
stmts (unique int id: @stmt,
int kind: int ref,
int parent: @stmt_parent ref,
int parent: @stmt_parent ref,
int idx: int ref,
varchar(900) tostring: string ref);
stmt_containers (unique int stmt: @stmt ref,
int container: @stmt_container ref);
jump_targets (unique int jump: @stmt ref,
int target: @stmt ref);
@@ -217,7 +217,7 @@ exprs (unique int id: @expr,
literals (varchar(900) value: string ref,
varchar(900) raw: string ref,
unique int expr: @expr_or_type ref);
enclosing_stmt (unique int expr: @expr_or_type ref,
int stmt: @stmt ref);
@@ -445,7 +445,7 @@ case @scope.kind of
scopenodes (unique int node: @ast_node ref,
int scope: @scope ref);
scopenesting (unique int inner: @scope ref,
int outer: @scope ref);
@@ -667,7 +667,7 @@ has_asserts_keyword(int node: @predicate_typeexpr ref);
@typed_ast_node = @expr | @typeexpr | @function;
ast_node_type(
unique int node: @typed_ast_node ref,
unique int node: @typed_ast_node ref,
int typ: @type ref);
declared_function_signature(
@@ -713,7 +713,7 @@ case @symbol.kind of
;
@type_with_symbol = @type_reference | @typevariable_type | @typeof_type | @unique_symbol_type;
@ast_node_with_symbol = @type_definition | @namespace_definition | @toplevel | @typeaccess | @namespace_access | @var_decl | @function | @invokeexpr | @import_declaration | @external_module_reference;
@ast_node_with_symbol = @type_definition | @namespace_definition | @toplevel | @typeaccess | @namespace_access | @var_decl | @function | @invokeexpr | @import_declaration | @external_module_reference | @external_module_declaration;
ast_node_symbol(
unique int node: @ast_node_with_symbol ref,
@@ -846,7 +846,7 @@ js_parse_errors (unique int id: @js_parse_error,
int toplevel: @toplevel ref,
varchar(900) message: string ref,
varchar(900) line: string ref);
// regular expressions
#keyset[parent, idx]
regexpterm (unique int id: @regexpterm,
@@ -854,7 +854,7 @@ regexpterm (unique int id: @regexpterm,
int parent: @regexpparent ref,
int idx: int ref,
varchar(900) tostring: string ref);
@regexpparent = @regexpterm | @regexp_literal | @string_literal | @add_expr;
case @regexpterm.kind of
@@ -972,7 +972,7 @@ case @json_value.kind of
// locations
@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr;
@locatable = @file
@locatable = @file
| @ast_node
| @comment
| @line

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Associate symbols with external module declarations
compatibility: backwards

View File

@@ -1,3 +1,12 @@
## 0.2.0
### Minor Analysis Improvements
* The `js/resource-exhaustion` query no longer treats the 3-argument version of `Buffer.from` as a sink,
since it does not allocate a new buffer.
## 0.1.4
## 0.1.3
### New Queries

View File

@@ -10,7 +10,7 @@
*/
import javascript
private import Declarations
private import Declarations.Declarations
from VarAccess acc, VarDecl decl, Variable var, StmtContainer sc
where

View File

@@ -10,7 +10,7 @@
*/
import javascript
private import Declarations
private import Declarations.Declarations
from Variable v, TopLevel tl, VarDecl decl, VarDecl redecl
where

View File

@@ -165,6 +165,9 @@ predicate whitelisted(UnusedLocal v) {
or
// ignore ambient declarations - too noisy
vd.isAmbient()
or
// ignore variables in template placeholders, as each placeholder sees a different copy of the variable
vd.getTopLevel() instanceof Templating::TemplateTopLevel
)
or
exists(Expr eval | eval instanceof DirectEval or eval instanceof GeneratedCodeExpr |

View File

@@ -0,0 +1,4 @@
---
category: breaking
---
* Contextual queries and the query libraries they depend on have been moved to the `codeql/javascript-all` package.

View File

@@ -0,0 +1 @@
## 0.1.4

View File

@@ -1,5 +1,6 @@
---
category: minorAnalysis
---
## 0.2.0
### Minor Analysis Improvements
* The `js/resource-exhaustion` query no longer treats the 3-argument version of `Buffer.from` as a sink,
since it does not allocate a new buffer.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.1.3
lastReleaseVersion: 0.2.0

View File

@@ -0,0 +1,42 @@
/**
* @name Unmodeled step
* @description A potential step from an argument to a return that has no data/taint step.
* @kind metric
* @metricType project
* @metricAggregate sum
* @tags meta
* @id js/meta/unmodeled-step
*/
import javascript
import meta.MetaMetrics
private import Expressions.ExprHasNoEffect
import meta.internal.TaintMetrics
predicate unmodeled(API::Node callee, API::CallNode call, DataFlow::Node pred, DataFlow::Node succ) {
callee.getACall() = call and
pred = call.getAnArgument() and
succ = call and
not inVoidContext(succ.asExpr()) and // void calls are irrelevant
not call.getAnArgument() = relevantTaintSink() and // calls with sinks are considered modeled
// we assume taint to the return value means the call is modeled
not (
TaintTracking::sharedTaintStep(_, succ)
or
DataFlow::SharedFlowStep::step(_, succ)
or
DataFlow::SharedFlowStep::step(_, succ, _, _)
or
DataFlow::SharedFlowStep::loadStep(_, succ, _)
or
DataFlow::SharedFlowStep::storeStep(_, succ, _)
or
DataFlow::SharedFlowStep::loadStoreStep(_, succ, _, _)
or
DataFlow::SharedFlowStep::loadStoreStep(_, succ, _)
) and
not pred.getFile() instanceof IgnoredFile and
not succ.getFile() instanceof IgnoredFile
}
select projectRoot(), count(DataFlow::Node pred, DataFlow::Node succ | unmodeled(_, _, pred, succ))

View File

@@ -1,5 +1,5 @@
name: codeql/javascript-queries
version: 0.1.4-dev
version: 0.2.1-dev
groups:
- javascript
- queries

View File

@@ -34,6 +34,7 @@ from Locatable loc, File f, int l, string name, string msg
where
expected(loc, f, l, name) and
not actual(_, f, l, name) and
name != "none" and
msg = "Failed to track " + name + " here."
or
actual(loc, f, l, name) and

View File

@@ -0,0 +1,32 @@
const lib = require('testlib');
function foo() {
return lib.foo(); // name: raw-await-source
}
async function test() {
const x = await foo();
const y = await x;
const z = await y;
z; // track: raw-await-source
}
async function exceptionThrower() {
throw {}; // name: raw-await-err
}
async function exceptionReThrower() {
const x = await exceptionThrower();
const y = x.catch(err => {
err; // track: none
});
return y;
}
async function exceptionCatcher() {
try {
await exceptionThrower();
} catch (err) {
err; // track: raw-await-err
}
}

View File

@@ -3235,6 +3235,92 @@ nodes
| tainted-access-paths.js:40:23:40:26 | path |
| tainted-access-paths.js:40:23:40:26 | path |
| tainted-access-paths.js:40:23:40:26 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:24:48:30 | req.url |
| tainted-access-paths.js:48:24:48:30 | req.url |
| tainted-access-paths.js:48:24:48:30 | req.url |
| tainted-access-paths.js:48:24:48:30 | req.url |
| tainted-access-paths.js:48:24:48:30 | req.url |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:49:10:49:13 | path |
| tainted-require.js:7:19:7:37 | req.param("module") |
| tainted-require.js:7:19:7:37 | req.param("module") |
| tainted-require.js:7:19:7:37 | req.param("module") |
@@ -8759,6 +8845,118 @@ edges
| tainted-access-paths.js:39:24:39:30 | req.url | tainted-access-paths.js:39:14:39:37 | url.par ... , true) |
| tainted-access-paths.js:39:24:39:30 | req.url | tainted-access-paths.js:39:14:39:37 | url.par ... , true) |
| tainted-access-paths.js:39:24:39:30 | req.url | tainted-access-paths.js:39:14:39:37 | url.par ... , true) |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:7:48:48 | path | tainted-access-paths.js:49:10:49:13 | path |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:37 | url.par ... , true) | tainted-access-paths.js:48:14:48:43 | url.par ... ).query |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:43 | url.par ... ).query | tainted-access-paths.js:48:14:48:48 | url.par ... ry.path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:14:48:48 | url.par ... ry.path | tainted-access-paths.js:48:7:48:48 | path |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:48:14:48:37 | url.par ... , true) |
| tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") |
| tainted-require.js:12:29:12:47 | req.param("module") | tainted-require.js:12:29:12:47 | req.param("module") |
| tainted-require.js:14:11:14:29 | req.param("module") | tainted-require.js:14:11:14:29 | req.param("module") |
@@ -10000,6 +10198,7 @@ edges
| tainted-access-paths.js:30:23:30:30 | obj.sub4 | tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:30:23:30:30 | obj.sub4 | This path depends on $@. | tainted-access-paths.js:6:24:6:30 | req.url | a user-provided value |
| tainted-access-paths.js:31:23:31:30 | obj.sub4 | tainted-access-paths.js:6:24:6:30 | req.url | tainted-access-paths.js:31:23:31:30 | obj.sub4 | This path depends on $@. | tainted-access-paths.js:6:24:6:30 | req.url | a user-provided value |
| tainted-access-paths.js:40:23:40:26 | path | tainted-access-paths.js:39:24:39:30 | req.url | tainted-access-paths.js:40:23:40:26 | path | This path depends on $@. | tainted-access-paths.js:39:24:39:30 | req.url | a user-provided value |
| tainted-access-paths.js:49:10:49:13 | path | tainted-access-paths.js:48:24:48:30 | req.url | tainted-access-paths.js:49:10:49:13 | path | This path depends on $@. | tainted-access-paths.js:48:24:48:30 | req.url | a user-provided value |
| tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value |
| tainted-require.js:12:29:12:47 | req.param("module") | tainted-require.js:12:29:12:47 | req.param("module") | tainted-require.js:12:29:12:47 | req.param("module") | This path depends on $@. | tainted-require.js:12:29:12:47 | req.param("module") | a user-provided value |
| tainted-require.js:14:11:14:29 | req.param("module") | tainted-require.js:14:11:14:29 | req.param("module") | tainted-require.js:14:11:14:29 | req.param("module") | This path depends on $@. | tainted-require.js:14:11:14:29 | req.param("module") | a user-provided value |

View File

@@ -40,4 +40,11 @@ var server2 = http.createServer(function(req, res) {
nodefs.readFileSync(path); // NOT OK
});
server2.listen();
server2.listen();
const chownr = require("chownr");
var server3 = http.createServer(function (req, res) {
let path = url.parse(req.url, true).query.path;
chownr(path, "someuid", "somegid", function (err) {}); // NOT OK
});

View File

@@ -1026,6 +1026,10 @@ nodes
| tst.js:476:20:476:22 | url |
| tst.js:486:22:486:24 | url |
| tst.js:486:22:486:24 | url |
| tst.js:491:23:491:35 | location.hash |
| tst.js:491:23:491:35 | location.hash |
| tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:491:23:491:45 | locatio ... bstr(1) |
| typeahead.js:20:13:20:45 | target |
| typeahead.js:20:22:20:45 | documen ... .search |
| typeahead.js:20:22:20:45 | documen ... .search |
@@ -2081,6 +2085,10 @@ edges
| tst.js:471:13:471:36 | documen ... .search | tst.js:471:13:471:46 | documen ... bstr(1) |
| tst.js:471:13:471:36 | documen ... .search | tst.js:471:13:471:46 | documen ... bstr(1) |
| tst.js:471:13:471:46 | documen ... bstr(1) | tst.js:471:7:471:46 | url |
| tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) |
| typeahead.js:20:13:20:45 | target | typeahead.js:21:12:21:17 | target |
| typeahead.js:20:22:20:45 | documen ... .search | typeahead.js:20:13:20:45 | target |
| typeahead.js:20:22:20:45 | documen ... .search | typeahead.js:20:13:20:45 | target |
@@ -2354,6 +2362,7 @@ edges
| tst.js:475:25:475:27 | url | tst.js:471:13:471:36 | documen ... .search | tst.js:475:25:475:27 | url | Cross-site scripting vulnerability due to $@. | tst.js:471:13:471:36 | documen ... .search | user-provided value |
| tst.js:476:20:476:22 | url | tst.js:471:13:471:36 | documen ... .search | tst.js:476:20:476:22 | url | Cross-site scripting vulnerability due to $@. | tst.js:471:13:471:36 | documen ... .search | user-provided value |
| tst.js:486:22:486:24 | url | tst.js:471:13:471:36 | documen ... .search | tst.js:486:22:486:24 | url | Cross-site scripting vulnerability due to $@. | tst.js:471:13:471:36 | documen ... .search | user-provided value |
| tst.js:491:23:491:45 | locatio ... bstr(1) | tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) | Cross-site scripting vulnerability due to $@. | tst.js:491:23:491:35 | location.hash | user-provided value |
| typeahead.js:25:18:25:20 | val | typeahead.js:20:22:20:45 | documen ... .search | typeahead.js:25:18:25:20 | val | Cross-site scripting vulnerability due to $@. | typeahead.js:20:22:20:45 | documen ... .search | user-provided value |
| v-html.vue:2:8:2:23 | v-html=tainted | v-html.vue:6:42:6:58 | document.location | v-html.vue:2:8:2:23 | v-html=tainted | Cross-site scripting vulnerability due to $@. | v-html.vue:6:42:6:58 | document.location | user-provided value |
| various-concat-obfuscations.js:4:4:4:31 | "<div>" ... </div>" | various-concat-obfuscations.js:2:16:2:39 | documen ... .search | various-concat-obfuscations.js:4:4:4:31 | "<div>" ... </div>" | Cross-site scripting vulnerability due to $@. | various-concat-obfuscations.js:2:16:2:39 | documen ... .search | user-provided value |

View File

@@ -1038,6 +1038,10 @@ nodes
| tst.js:476:20:476:22 | url |
| tst.js:486:22:486:24 | url |
| tst.js:486:22:486:24 | url |
| tst.js:491:23:491:35 | location.hash |
| tst.js:491:23:491:35 | location.hash |
| tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:491:23:491:45 | locatio ... bstr(1) |
| typeahead.js:9:28:9:30 | loc |
| typeahead.js:9:28:9:30 | loc |
| typeahead.js:9:28:9:30 | loc |
@@ -2143,6 +2147,10 @@ edges
| tst.js:471:13:471:36 | documen ... .search | tst.js:471:13:471:46 | documen ... bstr(1) |
| tst.js:471:13:471:36 | documen ... .search | tst.js:471:13:471:46 | documen ... bstr(1) |
| tst.js:471:13:471:46 | documen ... bstr(1) | tst.js:471:7:471:46 | url |
| tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) |
| tst.js:491:23:491:35 | location.hash | tst.js:491:23:491:45 | locatio ... bstr(1) |
| typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc |
| typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc |
| typeahead.js:9:28:9:30 | loc | typeahead.js:10:16:10:18 | loc |

View File

@@ -487,4 +487,6 @@ function urlStuff() {
}
window.open(location.hash.substr(1)); // OK - any JavaScript is executed in another context
}
navigation.navigate(location.hash.substr(1)); // NOT OK
}

View File

@@ -1,4 +1,13 @@
nodes
| jquery-plugin.js:11:27:11:31 | stuff |
| jquery-plugin.js:11:27:11:31 | stuff |
| jquery-plugin.js:11:34:11:40 | options |
| jquery-plugin.js:11:34:11:40 | options |
| jquery-plugin.js:12:31:12:37 | options |
| jquery-plugin.js:12:31:12:41 | options.foo |
| jquery-plugin.js:12:31:12:41 | options.foo |
| jquery-plugin.js:14:31:14:35 | stuff |
| jquery-plugin.js:14:31:14:35 | stuff |
| main.js:1:55:1:55 | s |
| main.js:1:55:1:55 | s |
| main.js:2:29:2:29 | s |
@@ -37,6 +46,10 @@ nodes
| main.js:66:35:66:41 | attrVal |
| main.js:67:63:67:69 | attrVal |
| main.js:67:63:67:69 | attrVal |
| main.js:79:34:79:36 | val |
| main.js:79:34:79:36 | val |
| main.js:81:35:81:37 | val |
| main.js:81:35:81:37 | val |
| typed.ts:1:39:1:39 | s |
| typed.ts:1:39:1:39 | s |
| typed.ts:2:29:2:29 | s |
@@ -53,6 +66,14 @@ nodes
| typed.ts:17:29:17:29 | s |
| typed.ts:17:29:17:29 | s |
edges
| jquery-plugin.js:11:27:11:31 | stuff | jquery-plugin.js:14:31:14:35 | stuff |
| jquery-plugin.js:11:27:11:31 | stuff | jquery-plugin.js:14:31:14:35 | stuff |
| jquery-plugin.js:11:27:11:31 | stuff | jquery-plugin.js:14:31:14:35 | stuff |
| jquery-plugin.js:11:27:11:31 | stuff | jquery-plugin.js:14:31:14:35 | stuff |
| jquery-plugin.js:11:34:11:40 | options | jquery-plugin.js:12:31:12:37 | options |
| jquery-plugin.js:11:34:11:40 | options | jquery-plugin.js:12:31:12:37 | options |
| jquery-plugin.js:12:31:12:37 | options | jquery-plugin.js:12:31:12:41 | options.foo |
| jquery-plugin.js:12:31:12:37 | options | jquery-plugin.js:12:31:12:41 | options.foo |
| main.js:1:55:1:55 | s | main.js:2:29:2:29 | s |
| main.js:1:55:1:55 | s | main.js:2:29:2:29 | s |
| main.js:1:55:1:55 | s | main.js:2:29:2:29 | s |
@@ -90,6 +111,10 @@ edges
| main.js:66:35:66:41 | attrVal | main.js:67:63:67:69 | attrVal |
| main.js:66:35:66:41 | attrVal | main.js:67:63:67:69 | attrVal |
| main.js:66:35:66:41 | attrVal | main.js:67:63:67:69 | attrVal |
| main.js:79:34:79:36 | val | main.js:81:35:81:37 | val |
| main.js:79:34:79:36 | val | main.js:81:35:81:37 | val |
| main.js:79:34:79:36 | val | main.js:81:35:81:37 | val |
| main.js:79:34:79:36 | val | main.js:81:35:81:37 | val |
| typed.ts:1:39:1:39 | s | typed.ts:2:29:2:29 | s |
| typed.ts:1:39:1:39 | s | typed.ts:2:29:2:29 | s |
| typed.ts:1:39:1:39 | s | typed.ts:2:29:2:29 | s |
@@ -105,6 +130,8 @@ edges
| typed.ts:16:11:16:21 | s | typed.ts:17:29:17:29 | s |
| typed.ts:16:15:16:21 | id("x") | typed.ts:16:11:16:21 | s |
#select
| jquery-plugin.js:12:31:12:41 | options.foo | jquery-plugin.js:11:34:11:40 | options | jquery-plugin.js:12:31:12:41 | options.foo | $@ based on $@ might later cause $@. | jquery-plugin.js:12:31:12:41 | options.foo | HTML construction | jquery-plugin.js:11:34:11:40 | options | library input | jquery-plugin.js:12:20:12:53 | "<span> ... /span>" | cross-site scripting |
| jquery-plugin.js:14:31:14:35 | stuff | jquery-plugin.js:11:27:11:31 | stuff | jquery-plugin.js:14:31:14:35 | stuff | $@ based on $@ might later cause $@. | jquery-plugin.js:14:31:14:35 | stuff | HTML construction | jquery-plugin.js:11:27:11:31 | stuff | library input | jquery-plugin.js:14:20:14:47 | "<span> ... /span>" | cross-site scripting |
| main.js:2:29:2:29 | s | main.js:1:55:1:55 | s | main.js:2:29:2:29 | s | $@ based on $@ might later cause $@. | main.js:2:29:2:29 | s | HTML construction | main.js:1:55:1:55 | s | library input | main.js:3:49:3:52 | html | cross-site scripting |
| main.js:7:49:7:49 | s | main.js:6:49:6:49 | s | main.js:7:49:7:49 | s | $@ based on $@ might later cause $@. | main.js:7:49:7:49 | s | XML parsing | main.js:6:49:6:49 | s | library input | main.js:8:48:8:66 | doc.documentElement | cross-site scripting |
| main.js:12:49:12:49 | s | main.js:11:60:11:60 | s | main.js:12:49:12:49 | s | $@ based on $@ might later cause $@. | main.js:12:49:12:49 | s | XML parsing | main.js:11:60:11:60 | s | library input | main.js:16:21:16:35 | xml.cloneNode() | cross-site scripting |
@@ -113,5 +140,6 @@ edges
| main.js:47:65:47:73 | this.step | main.js:52:41:52:41 | s | main.js:47:65:47:73 | this.step | $@ based on $@ might later cause $@. | main.js:47:65:47:73 | this.step | HTML construction | main.js:52:41:52:41 | s | library input | main.js:47:54:47:85 | "<span> ... /span>" | cross-site scripting |
| main.js:62:19:62:31 | settings.name | main.js:56:28:56:34 | options | main.js:62:19:62:31 | settings.name | $@ based on $@ might later cause $@. | main.js:62:19:62:31 | settings.name | HTML construction | main.js:56:28:56:34 | options | library input | main.js:62:11:62:40 | "<b>" + ... "</b>" | cross-site scripting |
| main.js:67:63:67:69 | attrVal | main.js:66:35:66:41 | attrVal | main.js:67:63:67:69 | attrVal | $@ based on $@ might later cause $@. | main.js:67:63:67:69 | attrVal | HTML construction | main.js:66:35:66:41 | attrVal | library input | main.js:67:47:67:78 | "<img a ... "\\"/>" | cross-site scripting |
| main.js:81:35:81:37 | val | main.js:79:34:79:36 | val | main.js:81:35:81:37 | val | $@ based on $@ might later cause $@. | main.js:81:35:81:37 | val | HTML construction | main.js:79:34:79:36 | val | library input | main.js:81:24:81:49 | "<span> ... /span>" | cross-site scripting |
| typed.ts:2:29:2:29 | s | typed.ts:1:39:1:39 | s | typed.ts:2:29:2:29 | s | $@ based on $@ might later cause $@. | typed.ts:2:29:2:29 | s | HTML construction | typed.ts:1:39:1:39 | s | library input | typed.ts:3:31:3:34 | html | cross-site scripting |
| typed.ts:8:40:8:40 | s | typed.ts:6:43:6:43 | s | typed.ts:8:40:8:40 | s | $@ based on $@ might later cause $@. | typed.ts:8:40:8:40 | s | HTML construction | typed.ts:6:43:6:43 | s | library input | typed.ts:8:29:8:52 | "<span> ... /span>" | cross-site scripting |

View File

@@ -7,3 +7,9 @@
}(function ($) {
$("<span>" + $.trim("foo") + "</span>"); // OK
}));
$.fn.myPlugin = function (stuff, options) {
$("#foo").html("<span>" + options.foo + "</span>"); // NOT OK
$("#foo").html("<span>" + stuff + "</span>"); // NOT OK
}

View File

@@ -75,3 +75,13 @@ module.exports.intentionalTemplate = function (obj) {
const html = "<span>" + obj.spanTemplate + "</span>"; // OK
document.querySelector("#template").innerHTML = html;
}
module.exports.types = function (val) {
if (typeof val === "string") {
$("#foo").html("<span>" + val + "</span>"); // NOT OK
} else if (typeof val === "number") {
$("#foo").html("<span>" + val + "</span>"); // OK
} else if (typeof val === "boolean") {
$("#foo").html("<span>" + val + "</span>"); // OK
}
}

View File

@@ -11,6 +11,10 @@ nodes
| lib/index.js:13:38:13:41 | data |
| lib/index.js:14:21:14:24 | data |
| lib/index.js:14:21:14:24 | data |
| lib/index.js:19:26:19:29 | data |
| lib/index.js:19:26:19:29 | data |
| lib/index.js:22:7:22:10 | data |
| lib/index.js:22:7:22:10 | data |
edges
| lib/index.js:1:35:1:38 | data | lib/index.js:2:21:2:24 | data |
| lib/index.js:1:35:1:38 | data | lib/index.js:2:21:2:24 | data |
@@ -24,7 +28,12 @@ edges
| lib/index.js:13:38:13:41 | data | lib/index.js:14:21:14:24 | data |
| lib/index.js:13:38:13:41 | data | lib/index.js:14:21:14:24 | data |
| lib/index.js:13:38:13:41 | data | lib/index.js:14:21:14:24 | data |
| lib/index.js:19:26:19:29 | data | lib/index.js:22:7:22:10 | data |
| lib/index.js:19:26:19:29 | data | lib/index.js:22:7:22:10 | data |
| lib/index.js:19:26:19:29 | data | lib/index.js:22:7:22:10 | data |
| lib/index.js:19:26:19:29 | data | lib/index.js:22:7:22:10 | data |
#select
| lib/index.js:2:21:2:24 | data | lib/index.js:1:35:1:38 | data | lib/index.js:2:21:2:24 | data | $@ flows to here and is later $@. | lib/index.js:1:35:1:38 | data | Library input | lib/index.js:2:15:2:30 | "(" + data + ")" | interpreted as code |
| lib/index.js:6:26:6:29 | name | lib/index.js:5:35:5:38 | name | lib/index.js:6:26:6:29 | name | $@ flows to here and is later $@. | lib/index.js:5:35:5:38 | name | Library input | lib/index.js:6:17:6:29 | "obj." + name | interpreted as code |
| lib/index.js:14:21:14:24 | data | lib/index.js:13:38:13:41 | data | lib/index.js:14:21:14:24 | data | $@ flows to here and is later $@. | lib/index.js:13:38:13:41 | data | Library input | lib/index.js:14:15:14:30 | "(" + data + ")" | interpreted as code |
| lib/index.js:22:7:22:10 | data | lib/index.js:19:26:19:29 | data | lib/index.js:22:7:22:10 | data | $@ flows to here and is later $@. | lib/index.js:19:26:19:29 | data | Library input | lib/index.js:25:24:25:26 | str | interpreted as code |

View File

@@ -12,4 +12,24 @@ export function safeAssignment(obj, value) {
global.unsafeDeserialize = function (data) {
return eval("(" + data + ")"); // NOT OK
}
}
const matter = require("gray-matter");
export function greySink(data) {
const str = `
---js
${data}
---
`
const res = matter(str);
console.log(res);
matter(str, { // OK
engines: {
js: function (data) {
console.log("NOPE");
}
}
});
}