Merge branch 'master' of https://github.com/github/codeql into pr/erik-krogh/3478

This commit is contained in:
Erik Krogh Kristensen
2020-05-18 07:51:19 +00:00
167 changed files with 7195 additions and 2317 deletions

View File

@@ -27,11 +27,10 @@ class DangerousScheme extends string {
/** Returns a node that refers to the scheme of `url`. */
DataFlow::SourceNode schemeOf(DataFlow::Node url) {
// url.split(":")[0]
exists(DataFlow::MethodCallNode split |
split.getMethodName() = "split" and
split.getArgument(0).getStringValue() = ":" and
result = split.getAPropertyRead("0") and
url = split.getReceiver()
exists(StringSplitCall split |
split.getSeparator() = ":" and
result = split.getASubstringRead(0) and
url = split.getBaseString()
)
or
// url.getScheme(), url.getProtocol(), getScheme(url), getProtocol(url)

View File

@@ -1,4 +1,4 @@
$("button").click(function () {
var target = this.attr("data-target");
var target = $(this).attr("data-target");
$(target).hide();
});

View File

@@ -1,4 +1,4 @@
$("button").click(function () {
var target = this.attr("data-target");
$.find(target).hide();
var target = $(this).attr("data-target");
$.find(target).hide();
});

View File

@@ -1,18 +1,21 @@
const pg = require('pg');
const pool = new pg.Pool(config);
const app = require("express")(),
pg = require("pg"),
pool = new pg.Pool(config);
function handler(req, res) {
app.get("search", function handler(req, res) {
// BAD: the category might have SQL special characters in it
var query1 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='"
+ req.params.category + "' ORDER BY PRICE";
var query1 =
"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='" +
req.params.category +
"' ORDER BY PRICE";
pool.query(query1, [], function(err, results) {
// process results
});
// GOOD: use parameters
var query2 = "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1"
+ " ORDER BY PRICE";
var query2 =
"SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY=$1" + " ORDER BY PRICE";
pool.query(query2, [req.params.category], function(err, results) {
// process results
// process results
});
}
});

View File

@@ -0,0 +1,99 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Sanitizing untrusted input for HTML meta-characters is an
important technique for preventing cross-site scripting attacks. But
even a sanitized input can be dangerous to use if it is modified
further before a browser treats it as HTML.
A seemingly innocent transformation that expands a
self-closing HTML tag from <code>&lt;div attr="{sanitized}"/&gt;</code>
to <code>&lt;div attr="{sanitized}"&gt;&lt;/div&gt;</code> may
in fact cause cross-site scripting vulnerabilities.
</p>
</overview>
<recommendation>
<p>
Use a well-tested sanitization library if at all
possible, and avoid modifying sanitized values further before treating
them as HTML.
</p>
</recommendation>
<example>
<p>
The following function transforms a self-closing HTML tag
to a pair of open/close tags. It does so for all non-<code>img</code>
and non-<code>area</code> tags, by using a regular expression with two
capture groups. The first capture group corresponds to the name of the
tag, and the second capture group to the content of the tag.
</p>
<sample src="examples/UnsafeHtmlExpansion.js" />
<p>
While it is generally known regular expressions are
ill-suited for parsing HTML, variants of this particular transformation
pattern have long been considered safe.
</p>
<p>
However, the function is not safe. As an example, consider
the following string:
</p>
<sample src="examples/UnsafeHtmlExpansion-original.html" />
<p>
When the above function transforms the string, it becomes
a string that results in an alert when a browser treats it as HTML.
</p>
<sample src="examples/UnsafeHtmlExpansion-transformed.html" />
</example>
<references>
<li>jQuery:
<a href="https://blog.jquery.com/2020/04/10/jquery-3-5-0-released/">Security fixes in jQuery 3.5.0</a>
</li>
<li>
OWASP:
<a href="https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html">DOM based
XSS Prevention Cheat Sheet</a>.
</li>
<li>
OWASP:
<a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html">XSS
(Cross Site Scripting) Prevention Cheat Sheet</a>.
</li>
<li>
OWASP
<a href="https://owasp.org/www-community/Types_of_Cross-Site_Scripting">Types of Cross-Site</a>.
</li>
<li>
Wikipedia: <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">Cross-site scripting</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,58 @@
/**
* @name Unsafe expansion of self-closing HTML tag
* @description Using regular expressions to expand self-closing HTML
* tags may lead to cross-site scripting vulnerabilities.
* @kind problem
* @problem.severity warning
* @precision very-high
* @id js/unsafe-html-expansion
* @tags correctness
* security
* external/cwe/cwe-079
* external/cwe/cwe-116
*/
import javascript
/**
* A regular expression that captures the name and content of a
* self-closing HTML tag such as `<div id='foo'/>`.
*/
class SelfClosingTagRecognizer extends DataFlow::RegExpCreationNode {
SelfClosingTagRecognizer() {
exists(RegExpSequence seq, RegExpGroup name, RegExpGroup content |
// `/.../g`
RegExp::isGlobal(this.getFlags()) and
this.getRoot() = seq.getRootTerm() and
// `/<.../`
seq.getChild(0).getConstantValue() = "<" and
// `/...\/>/`
seq.getLastChild().getPredecessor().getConstantValue() = "/" and
seq.getLastChild().getConstantValue() = ">" and
// `/...((...)...).../`
seq.getAChild() = content and
content.getNumber() = 1 and
name.getNumber() = 2 and
name = content.getChild(0).(RegExpSequence).getChild(0) and
// `/...(([a-z]+)...).../` or `/...(([a-z][...]*)...).../`
exists(RegExpQuantifier quant | name.getAChild*() = quant |
quant instanceof RegExpStar or
quant instanceof RegExpPlus
) and
// `/...((...)[^>]*).../`
exists(RegExpCharacterClass lazy |
name.getSuccessor().(RegExpStar).getChild(0) = lazy and
lazy.isInverted() and
lazy.getAChild().getConstantValue() = ">"
)
)
}
}
from SelfClosingTagRecognizer regexp, StringReplaceCall replace
where
regexp.getAReference().flowsTo(replace.getArgument(0)) and
replace.getRawReplacement().mayHaveStringValue("<$1></$2>")
select replace,
"This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value.",
regexp, "this regular expression"

View File

@@ -0,0 +1,3 @@
<div alt="
<x" title="/>
<img src=url404 onerror=alert(1)>"/>

View File

@@ -0,0 +1,3 @@
<img alt="
<x" title="></x" >
<img src=url404 onerror=alert(1)>"/>

View File

@@ -0,0 +1,4 @@
function expandSelfClosingTags(html) {
var rxhtmlTag = /<(?!img|area)(([a-z][^\w\/>]*)[^>]*)\/>/gi;
return html.replace(rxhtmlTag, "<$1></$2>"); // BAD
}

View File

@@ -1 +1,7 @@
console.log("Unauthorized access attempt by " + user, ip);
const app = require("express")();
app.get("unauthorized", function handler(req, res) {
let user = req.query.user;
let ip = req.connection.remoteAddress;
console.log("Unauthorized access attempt by " + user, ip);
});

View File

@@ -1 +1,7 @@
console.log("Unauthorized access attempt by %s", user, ip);
const app = require("express")();
app.get("unauthorized", function handler(req, res) {
let user = req.query.user;
let ip = req.connection.remoteAddress;
console.log("Unauthorized access attempt by %s", user, ip);
});

View File

@@ -1,7 +1,9 @@
const crypto = require('crypto');
var secretText = obj.getSecretText();
const desCipher = crypto.createCipher('des', key);
let desEncrypted = cipher.write(secretText, 'utf8', 'hex'); // BAD: weak encryption
let desEncrypted = desCipher.write(secretText, 'utf8', 'hex'); // BAD: weak encryption
const aesCipher = crypto.createCipher('aes-128', key);
let aesEncrypted = cipher.update(secretText, 'utf8', 'hex'); // GOOD: strong encryption
let aesEncrypted = aesCipher.update(secretText, 'utf8', 'hex'); // GOOD: strong encryption

View File

@@ -1,11 +1,11 @@
var express = require('express')
var cookieParser = require('cookie-parser')
var passport = require('passport')
var app = require("express")(),
cookieParser = require("cookie-parser"),
passport = require("passport");
var app = express()
app.use(cookieParser());
app.use(passport.authorize({ session: true }));
app.use(cookieParser())
app.use(passport.authorize({ session: true }))
app.post('/changeEmail', ..., function (req, res) {
})
app.post("/changeEmail", function(req, res) {
let newEmail = req.cookies["newEmail"];
// ...
});

View File

@@ -1,13 +1,12 @@
var express = require('express')
var cookieParser = require('cookie-parser')
var passport = require('passport')
var csrf = require('csurf')
var app = require("express")(),
cookieParser = require("cookie-parser"),
passport = require("passport"),
csrf = require("csurf");
var app = express()
app.use(cookieParser())
app.use(passport.authorize({ session: true }))
app.use(csrf({ cookie:true }))
app.post('/changeEmail', ..., function (req, res) {
})
app.use(cookieParser());
app.use(passport.authorize({ session: true }));
app.use(csrf({ cookie: true }));
app.post("/changeEmail", function(req, res) {
let newEmail = req.cookies["newEmail"];
// ...
});

View File

@@ -21,11 +21,10 @@ import semmle.javascript.DynamicPropertyAccess
*
* We restrict this to parameter nodes to focus on "deep assignment" functions.
*/
class SplitCall extends MethodCallNode {
class SplitCall extends StringSplitCall {
SplitCall() {
getMethodName() = "split" and
getArgument(0).mayHaveStringValue(".") and
getReceiver().getALocalSource() instanceof ParameterNode
getSeparator() = "." and
getBaseString().getALocalSource() instanceof ParameterNode
}
}

View File

@@ -1,6 +1,7 @@
const jsyaml = require("js-yaml");
const app = require("express")(),
jsyaml = require("js-yaml");
function requestHandler(req, res) {
app.get("load", function(req, res) {
let data = jsyaml.load(req.params.data);
// ...
}
});

View File

@@ -1,6 +1,7 @@
const jsyaml = require("js-yaml");
const app = require("express")(),
jsyaml = require("js-yaml");
function requestHandler(req, res) {
app.get("load", function(req, res) {
let data = jsyaml.safeLoad(req.params.data);
// ...
}
});

View File

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

View File

@@ -1,3 +1,5 @@
const app = require("express")();
const VALID_REDIRECT = "http://cwe.mitre.org/data/definitions/601.html";
app.get('/some/path', function(req, res) {

View File

@@ -1,2 +1,7 @@
const libxml = require('libxmljs');
var doc = libxml.parseXml(xmlSrc, { noent: true });
const app = require("express")(),
libxml = require("libxmljs");
app.post("upload", (req, res) => {
let xmlSrc = req.body,
doc = libxml.parseXml(xmlSrc, { noent: true });
});

View File

@@ -1,2 +1,7 @@
const libxml = require('libxmljs');
var doc = libxml.parseXml(xmlSrc);
const app = require("express")(),
libxml = require("libxmljs");
app.post("upload", (req, res) => {
let xmlSrc = req.body,
doc = libxml.parseXml(xmlSrc);
});

View File

@@ -1,5 +1,10 @@
const expat = require('node-expat');
var parser = new expat.Parser();
parser.on('startElement', handleStart);
parser.on('text', handleText);
parser.write(xmlSrc);
const app = require("express")(),
expat = require("node-expat");
app.post("upload", (req, res) => {
let xmlSrc = req.body,
parser = new expat.Parser();
parser.on("startElement", handleStart);
parser.on("text", handleText);
parser.write(xmlSrc);
});

View File

@@ -1,5 +1,10 @@
const sax = require('sax');
var parser = sax.parser(true);
parser.onopentag = handleStart;
parser.ontext = handleText;
parser.write(xmlSrc);
const app = require("express")(),
sax = require("sax");
app.post("upload", (req, res) => {
let xmlSrc = req.body,
parser = sax.parser(true);
parser.onopentag = handleStart;
parser.ontext = handleText;
parser.write(xmlSrc);
});

View File

@@ -1,10 +1,10 @@
const pg = require('pg')
const pg = require("pg");
const client = new pg.Client({
user: 'dbuser',
host: 'database.server.com',
database: 'mydb',
password: 'secretpassword',
port: 3211,
})
client.connect()
user: "bob",
host: "database.server.com",
database: "mydb",
password: "correct-horse-battery-staple",
port: 3211
});
client.connect();

View File

@@ -1,15 +1,15 @@
var express = require('express'),
path = require('path'),
var app = express();
var app = require("express")(),
path = require("path");
app.get('/user-files', function(req, res) {
var file = req.param('file');
if (file.indexOf('..') !== -1) { // BAD
// forbid paths outside the /public directory
res.status(400).send('Bad request');
} else {
var absolute = path.resolve('/public/' + file);
console.log("Sending file: %s", absolute);
res.sendFile(absolute);
}
app.get("/user-files", function(req, res) {
var file = req.param("file");
if (file.indexOf("..") !== -1) {
// BAD
// forbid paths outside the /public directory
res.status(400).send("Bad request");
} else {
var absolute = path.resolve("/public/" + file);
console.log("Sending file: %s", absolute);
res.sendFile(absolute);
}
});

View File

@@ -1,15 +1,15 @@
var express = require('express'),
path = require('path'),
var app = express();
var app = require("express")(),
path = require("path");
app.get('/user-files', function(req, res) {
var file = req.param('file');
if (typeof path !== 'string' || path.indexOf('..') !== -1) { // GOOD
// forbid paths outside the /public directory
res.status(400).send('Bad request');
} else {
var full = path.resolve('/public/' + file);
console.log("Sending file: %s", full);
res.sendFile(full);
}
app.get("/user-files", function(req, res) {
var file = req.param("file");
if (typeof path !== 'string' || file.indexOf("..") !== -1) {
// BAD
// forbid paths outside the /public directory
res.status(400).send("Bad request");
} else {
var absolute = path.resolve("/public/" + file);
console.log("Sending file: %s", absolute);
res.sendFile(absolute);
}
});

View File

@@ -1,5 +1,5 @@
const crypto = require("crypto");
function hashPassword(password) {
var crypto = require("crypto");
var hasher = crypto.createHash('md5');
var hashed = hasher.update(password).digest("hex"); // BAD
return hashed;

View File

@@ -1,5 +1,5 @@
const bcrypt = require("bcrypt");
function hashPassword(password, salt) {
var bcrypt = require('bcrypt');
var hashed = bcrypt.hashSync(password, salt); // GOOD
return hashed;
var hashed = bcrypt.hashSync(password, salt); // GOOD
return hashed;
}

View File

@@ -2,7 +2,7 @@ import http from 'http';
import url from 'url';
var server = http.createServer(function(req, res) {
var target = url.parse(request.url, true).query.target;
var target = url.parse(req.url, true).query.target;
// BAD: `target` is controlled by the attacker
http.get('https://' + target + ".example.com/data/", res => {

View File

@@ -2,7 +2,7 @@ import http from 'http';
import url from 'url';
var server = http.createServer(function(req, res) {
var target = url.parse(request.url, true).query.target;
var target = url.parse(req.url, true).query.target;
var subdomain;
if (target === 'EU') {

View File

@@ -192,7 +192,7 @@ private class AmdDependencyPath extends PathExprCandidate {
}
/** A constant path element appearing in an AMD dependency expression. */
private class ConstantAmdDependencyPathElement extends PathExprInModule, ConstantString {
private class ConstantAmdDependencyPathElement extends PathExpr, ConstantString {
ConstantAmdDependencyPathElement() { this = any(AmdDependencyPath amd).getAPart() }
override string getValue() { result = getStringValue() }

View File

@@ -53,7 +53,7 @@ class ES2015Module extends Module {
class ImportDeclaration extends Stmt, Import, @importdeclaration {
override ES2015Module getEnclosingModule() { result = getTopLevel() }
override PathExprInModule getImportedPath() { result = getChildExpr(-1) }
override PathExpr getImportedPath() { result = getChildExpr(-1) }
/** Gets the `i`th import specifier of this import declaration. */
ImportSpecifier getSpecifier(int i) { result = getChildExpr(i) }
@@ -82,7 +82,7 @@ class ImportDeclaration extends Stmt, Import, @importdeclaration {
}
/** A literal path expression appearing in an `import` declaration. */
private class LiteralImportPath extends PathExprInModule, ConstantString {
private class LiteralImportPath extends PathExpr, ConstantString {
LiteralImportPath() { exists(ImportDeclaration req | this = req.getChildExpr(-1)) }
override string getValue() { result = getStringValue() }
@@ -622,7 +622,7 @@ abstract class ReExportDeclaration extends ExportDeclaration {
}
/** A literal path expression appearing in a re-export declaration. */
private class LiteralReExportPath extends PathExprInModule, ConstantString {
private class LiteralReExportPath extends PathExpr, ConstantString {
LiteralReExportPath() { exists(ReExportDeclaration bred | this = bred.getImportedPath()) }
override string getValue() { result = getStringValue() }

View File

@@ -2614,7 +2614,7 @@ class DynamicImportExpr extends @dynamicimport, Expr, Import {
}
/** A literal path expression appearing in a dynamic import. */
private class LiteralDynamicImportPath extends PathExprInModule, ConstantString {
private class LiteralDynamicImportPath extends PathExpr, ConstantString {
LiteralDynamicImportPath() {
exists(DynamicImportExpr di | this.getParentExpr*() = di.getSource())
}

View File

@@ -185,12 +185,14 @@ abstract class Import extends ASTNode {
}
/**
* DEPRECATED. Use `PathExpr` instead.
*
* A path expression that appears in a module and is resolved relative to it.
*/
abstract class PathExprInModule extends PathExpr {
PathExprInModule() { exists(getEnclosingModule()) }
override Folder getSearchRoot(int priority) {
getEnclosingModule().searchRoot(this, result, priority)
abstract deprecated class PathExprInModule extends PathExpr {
PathExprInModule() {
this.(Expr).getTopLevel() instanceof Module
or
this.(Comment).getTopLevel() instanceof Module
}
}

View File

@@ -266,14 +266,14 @@ private class RequirePath extends PathExprCandidate {
}
/** A constant path element appearing in a call to `require` or `require.resolve`. */
private class ConstantRequirePathElement extends PathExprInModule, ConstantString {
private class ConstantRequirePathElement extends PathExpr, ConstantString {
ConstantRequirePathElement() { this = any(RequirePath rp).getAPart() }
override string getValue() { result = getStringValue() }
}
/** A `__dirname` path expression. */
private class DirNamePath extends PathExprInModule, VarAccess {
private class DirNamePath extends PathExpr, VarAccess {
DirNamePath() {
getName() = "__dirname" and
getVariable().getScope() instanceof ModuleScope
@@ -283,7 +283,7 @@ private class DirNamePath extends PathExprInModule, VarAccess {
}
/** A `__filename` path expression. */
private class FileNamePath extends PathExprInModule, VarAccess {
private class FileNamePath extends PathExpr, VarAccess {
FileNamePath() {
getName() = "__filename" and
getVariable().getScope() instanceof ModuleScope
@@ -296,7 +296,7 @@ private class FileNamePath extends PathExprInModule, VarAccess {
* A path expression of the form `path.join(p, "...")` where
* `p` is also a path expression.
*/
private class JoinedPath extends PathExprInModule, @callexpr {
private class JoinedPath extends PathExpr, @callexpr {
JoinedPath() {
exists(MethodCallExpr call | call = this |
call.getReceiver().(VarAccess).getName() = "path" and

View File

@@ -112,7 +112,7 @@ class MainModulePath extends PathExpr, @json_string {
override string getValue() { result = this.(JSONString).getValue() }
override Folder getSearchRoot(int priority) {
override Folder getAdditionalSearchRoot(int priority) {
priority = 0 and
result = pkg.getFile().getParentContainer()
}

View File

@@ -174,17 +174,6 @@ abstract class PathString extends string {
Path resolve(Folder root) { result = resolveUpTo(getNumComponent(), root) }
}
/**
* Non-abstract base class for path expressions.
*/
private class PathExprBase extends Locatable {
// We must put getEnclosingModule here for it to be usable in the characteristic predicate of PathExprInModule
/** Gets the module containing this path expression, if any. */
Module getEnclosingModule() {
result = this.(Expr).getTopLevel() or result = this.(Comment).getTopLevel()
}
}
/**
* An expression whose value represents a (relative or absolute) file system path.
*
@@ -197,12 +186,25 @@ private class PathExprBase extends Locatable {
* as their highest-priority root, with default library paths as additional roots
* of lower priority.
*/
abstract class PathExpr extends PathExprBase {
abstract class PathExpr extends Locatable {
/** Gets the (unresolved) path represented by this expression. */
abstract string getValue();
/** Gets the root folder of priority `priority` associated with this path expression. */
abstract Folder getSearchRoot(int priority);
Folder getSearchRoot(int priority) {
// We default to the enclosing module's search root, though this may be overridden.
getEnclosingModule().searchRoot(this, result, priority)
or
result = getAdditionalSearchRoot(priority)
}
/**
* INTERNAL. Use `getSearchRoot` instead.
*
* Can be overridden by subclasses of `PathExpr` to provide additional search roots
* without overriding `getSearchRoot`.
*/
Folder getAdditionalSearchRoot(int priority) { none() }
/** Gets the `i`th component of this path. */
string getComponent(int i) { result = getValue().(PathString).getComponent(i) }
@@ -246,6 +248,11 @@ abstract class PathExpr extends PathExprBase {
/** Gets the file or folder that this path refers to. */
Container resolve() { result = resolveUpTo(getNumComponent()) }
/** Gets the module containing this path expression, if any. */
Module getEnclosingModule() {
result = this.(Expr).getTopLevel() or result = this.(Comment).getTopLevel()
}
}
/** A path string derived from a path expression. */
@@ -279,8 +286,8 @@ private class ConcatPath extends PathExpr {
)
}
override Folder getSearchRoot(int priority) {
result = this.(AddExpr).getAnOperand().(PathExpr).getSearchRoot(priority)
override Folder getAdditionalSearchRoot(int priority) {
result = this.(AddExpr).getAnOperand().(PathExpr).getAdditionalSearchRoot(priority)
}
}

View File

@@ -146,3 +146,37 @@ class StringReplaceCall extends DataFlow::MethodCallNode {
)
}
}
/**
* A call to `String.prototype.split`.
*
* We heuristically include any call to a method called `split`, provided it either
* has one or two arguments, or local data flow suggests that the receiver may be a string.
*/
class StringSplitCall extends DataFlow::MethodCallNode {
StringSplitCall() {
this.getMethodName() = "split" and
(getNumArgument() = [1, 2] or getReceiver().mayHaveStringValue(_))
}
/**
* Gets a string that determines where the string is split.
*/
string getSeparator() {
getArgument(0).mayHaveStringValue(result)
or
result =
getArgument(0).getALocalSource().(DataFlow::RegExpCreationNode).getRoot().getAMatchedString()
}
/**
* Gets the DataFlow::Node for the base string that is split.
*/
DataFlow::Node getBaseString() { result = getReceiver() }
/**
* Gets a read of the `i`th element from the split string.
*/
bindingset[i]
DataFlow::Node getASubstringRead(int i) { result = getAPropertyRead(i.toString()) }
}

View File

@@ -213,7 +213,7 @@ class ExternalModuleReference extends Expr, Import, @externalmodulereference {
}
/** A literal path expression appearing in an external module reference. */
private class LiteralExternalModulePath extends PathExprInModule, ConstantString {
private class LiteralExternalModulePath extends PathExpr, ConstantString {
LiteralExternalModulePath() {
exists(ExternalModuleReference emr | this.getParentExpr*() = emr.getExpression())
}

View File

@@ -1,42 +1,5 @@
/**
* Provides machinery for performing backward data-flow exploration.
*
* Importing this module effectively makes all data-flow and taint-tracking configurations
* ignore their `isSource` predicate. Instead, flow is tracked from any _initial node_ (that is,
* a node without incoming flow) to a sink node. All initial nodes are then treated as source
* nodes.
*
* Data-flow exploration cannot be used with configurations depending on other configurations.
*
* NOTE: This library should only be used for debugging, not in production code. Backward
* exploration in particular does not scale on non-trivial code bases and hence is of limited
* usefulness as it stands.
* Alias for the library `semmle.javascript.explore.BackwardDataFlow`.
*/
import javascript
private class BackwardExploringConfiguration extends DataFlow::Configuration {
DataFlow::Configuration cfg;
BackwardExploringConfiguration() { this = cfg }
override predicate isSource(DataFlow::Node node) { any() }
override predicate isSource(DataFlow::Node node, DataFlow::FlowLabel lbl) { any() }
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
exists(DataFlow::PathNode src, DataFlow::PathNode snk | hasFlowPath(src, snk) |
source = src.getNode() and
sink = snk.getNode()
)
}
override predicate hasFlowPath(DataFlow::SourcePathNode source, DataFlow::SinkPathNode sink) {
exists(DataFlow::MidPathNode first |
source.getConfiguration() = this and
source.getASuccessor() = first and
not exists(DataFlow::MidPathNode mid | mid.getASuccessor() = first) and
first.getASuccessor*() = sink
)
}
}
import semmle.javascript.explore.BackwardDataFlow

View File

@@ -536,6 +536,14 @@ module DataFlow {
*/
abstract Expr getPropertyNameExpr();
/**
* Holds if this property reference may access a property named `propName`.
*/
predicate mayHavePropertyName(string propName) {
propName = this.getPropertyName() or
this.getPropertyNameExpr().flow().mayHaveStringValue(propName)
}
/**
* Gets the name of the property being read or written,
* if it can be statically determined.

View File

@@ -1,40 +1,5 @@
/**
* Provides machinery for performing forward data-flow exploration.
*
* Importing this module effectively makes all data-flow and taint-tracking configurations
* ignore their `isSink` predicate. Instead, flow is tracked from source nodes as far as
* possible, until a _terminal node_ (that is, a node without any outgoing flow) is reached.
* All terminal nodes are then treated as sink nodes.
*
* Data-flow exploration cannot be used with configurations depending on other configurations.
*
* NOTE: This library should only be used for debugging, not in production code.
* Alias for the library `semmle.javascript.explore.ForwardDataFlow`.
*/
import javascript
private class ForwardExploringConfiguration extends DataFlow::Configuration {
DataFlow::Configuration cfg;
ForwardExploringConfiguration() { this = cfg }
override predicate isSink(DataFlow::Node node) { any() }
override predicate isSink(DataFlow::Node node, DataFlow::FlowLabel lbl) { any() }
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
exists(DataFlow::PathNode src, DataFlow::PathNode snk | hasFlowPath(src, snk) |
source = src.getNode() and
sink = snk.getNode()
)
}
override predicate hasFlowPath(DataFlow::SourcePathNode source, DataFlow::SinkPathNode sink) {
exists(DataFlow::MidPathNode last |
source.getConfiguration() = this and
source.getASuccessor*() = last and
not last.getASuccessor() instanceof DataFlow::MidPathNode and
last.getASuccessor() = sink
)
}
}
import semmle.javascript.explore.ForwardDataFlow

View File

@@ -697,6 +697,7 @@ module ModuleImportNode {
*
* This predicate can be extended by subclassing `ModuleImportNode::Range`.
*/
cached
ModuleImportNode moduleImport(string path) { result.getPath() = path }
/**

View File

@@ -0,0 +1,42 @@
/**
* Provides machinery for performing backward data-flow exploration.
*
* Importing this module effectively makes all data-flow and taint-tracking configurations
* ignore their `isSource` predicate. Instead, flow is tracked from any _initial node_ (that is,
* a node without incoming flow) to a sink node. All initial nodes are then treated as source
* nodes.
*
* Data-flow exploration cannot be used with configurations depending on other configurations.
*
* NOTE: This library should only be used for debugging and exploration, not in production code.
* Backward exploration in particular does not scale on non-trivial code bases and hence is of limited
* usefulness as it stands.
*/
import javascript
private class BackwardExploringConfiguration extends DataFlow::Configuration {
DataFlow::Configuration cfg;
BackwardExploringConfiguration() { this = cfg }
override predicate isSource(DataFlow::Node node) { any() }
override predicate isSource(DataFlow::Node node, DataFlow::FlowLabel lbl) { any() }
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
exists(DataFlow::PathNode src, DataFlow::PathNode snk | hasFlowPath(src, snk) |
source = src.getNode() and
sink = snk.getNode()
)
}
override predicate hasFlowPath(DataFlow::SourcePathNode source, DataFlow::SinkPathNode sink) {
exists(DataFlow::MidPathNode first |
source.getConfiguration() = this and
source.getASuccessor() = first and
not exists(DataFlow::MidPathNode mid | mid.getASuccessor() = first) and
first.getASuccessor*() = sink
)
}
}

View File

@@ -0,0 +1,85 @@
/**
* Provides predicates for visualizing the call paths leading to or from a specific function.
*
* It defines three predicates: `callEdge`, `isStartOfCallPath` and `isEndOfCallPath`,
* as well as the `nodes` and `edges` predicates needed for a path problem query.
*
* To use this library, make sure the query has `@kind path-problem`
* and selects columns appropriate for a path problem query.
* For example:
* ```
* import javascript
* import semmle.javascript.explore.CallGraph
* import DataFlow
*
* from InvokeNode invoke, FunctionNode function
* where callEdge*(invoke, function)
* and isStartOfCallPath(invoke)
* and function.getName() = "targetFunction"
* select invoke, invoke, function, "Call path to 'targetFunction'"
* ```
*
* NOTE: This library should only be used for debugging and exploration, not in production code.
*/
import javascript
private import DataFlow
/**
* Holds if `pred -> succ` is an edge in the call graph.
*
* There are edges from calls to their callees,
* and from functions to their contained calls and in some cases
* their inner functions to model functions invoked indirectly
* by being passed to another call.
*/
predicate callEdge(Node pred, Node succ) {
exists(InvokeNode invoke, Function f |
invoke.getACallee() = f and
pred = invoke and
succ = f.flow()
or
invoke.getContainer() = f and
pred = f.flow() and
succ = invoke
)
or
exists(Function inner, Function outer |
inner.getEnclosingContainer() = outer and
not inner = outer.getAReturnedExpr() and
pred = outer.flow() and
succ = inner.flow()
)
}
/** Holds if `pred -> succ` is an edge in the call graph. */
query predicate edges = callEdge/2;
/** Holds if `node` is part of the call graph. */
query predicate nodes(Node node) {
node instanceof InvokeNode or
node instanceof FunctionNode
}
/** Gets a call in a function that has no known call sites. */
private InvokeNode rootCall() { not any(InvokeNode i).getACallee() = result.getContainer() }
/**
* Holds if `invoke` should be used as the starting point of a call path.
*/
predicate isStartOfCallPath(InvokeNode invoke) {
// `invoke` should either be a root call or be part of a cycle with no root.
// An equivalent requirement is that `invoke` is not reachable from a root.
not callEdge+(rootCall(), invoke)
}
/** Gets a function that contains no calls to other functions. */
private FunctionNode leafFunction() { not callEdge(result, _) }
/**
* Holds if `fun` should be used as the end point of a call path.
*/
predicate isEndOfCallPath(FunctionNode fun) {
// `fun` should either be a leaf function or part of a cycle with no leaves.
not callEdge+(fun, leafFunction())
}

View File

@@ -0,0 +1,40 @@
/**
* Provides machinery for performing forward data-flow exploration.
*
* Importing this module effectively makes all data-flow and taint-tracking configurations
* ignore their `isSink` predicate. Instead, flow is tracked from source nodes as far as
* possible, until a _terminal node_ (that is, a node without any outgoing flow) is reached.
* All terminal nodes are then treated as sink nodes.
*
* Data-flow exploration cannot be used with configurations depending on other configurations.
*
* NOTE: This library should only be used for debugging and exploration, not in production code.
*/
import javascript
private class ForwardExploringConfiguration extends DataFlow::Configuration {
DataFlow::Configuration cfg;
ForwardExploringConfiguration() { this = cfg }
override predicate isSink(DataFlow::Node node) { any() }
override predicate isSink(DataFlow::Node node, DataFlow::FlowLabel lbl) { any() }
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
exists(DataFlow::PathNode src, DataFlow::PathNode snk | hasFlowPath(src, snk) |
source = src.getNode() and
sink = snk.getNode()
)
}
override predicate hasFlowPath(DataFlow::SourcePathNode source, DataFlow::SinkPathNode sink) {
exists(DataFlow::MidPathNode last |
source.getConfiguration() = this and
source.getASuccessor*() = last and
not last.getASuccessor() instanceof DataFlow::MidPathNode and
last.getASuccessor() = sink
)
}
}

View File

@@ -7,24 +7,104 @@
import javascript
module ConnectExpressShared {
/**
* String representing the signature of a route handler, that is,
* the list of parameters taken by the route handler.
*
* Concretely this is a comma-separated list of parameter kinds, which can be either
* `request`, `response`, `next`, `error`, or `parameter`, but this is considered an
* implementation detail.
*/
private class RouteHandlerSignature extends string {
RouteHandlerSignature() {
this = "request,response" or
this = "request,response,next" or
this = "request,response,next,parameter" or
this = "error,request,response,next"
}
/** Gets the index of the parameter corresonding to the given `kind`, if any. */
pragma[noinline]
int getParameterIndex(string kind) { this.splitAt(",", result) = kind }
/** Gets the number of parameters taken by this signature. */
pragma[noinline]
int getArity() { result = count(getParameterIndex(_)) }
/** Holds if this signature takes a parameter of the given kind. */
predicate has(string kind) { exists(getParameterIndex(kind)) }
}
private module RouteHandlerSignature {
/** Gets the signature corresonding to `(req, res, next, param) => {...}`. */
RouteHandlerSignature requestResponseNextParameter() {
result = "request,response,next,parameter"
}
/** Gets the signature corresonding to `(req, res, next) => {...}`. */
RouteHandlerSignature requestResponseNext() { result = "request,response,next" }
/** Gets the signature corresonding to `(err, req, res, next) => {...}`. */
RouteHandlerSignature errorRequestResponseNext() { result = "error,request,response,next" }
}
/**
* Holds if `fun` appears to match the given signature based on parameter naming.
*/
private predicate matchesSignature(Function function, RouteHandlerSignature sig) {
function.getNumParameter() = sig.getArity() and
function.getParameter(sig.getParameterIndex("request")).getName() = ["req", "request"] and
function.getParameter(sig.getParameterIndex("response")).getName() = ["res", "response"] and
(
sig.has("next")
implies
function.getParameter(sig.getParameterIndex("next")).getName() = ["next", "cb"]
)
}
/**
* Gets the parameter corresonding to the given `kind`, where `routeHandler` is interpreted as a
* route handler with the signature `sig`.
*
* This does not check if the function is actually a route handler or matches the signature in any way,
* so the caller should restrict the function accordingly.
*/
pragma[inline]
private Parameter getRouteHandlerParameter(
Function routeHandler, RouteHandlerSignature sig, string kind
) {
result = routeHandler.getParameter(sig.getParameterIndex(kind))
}
/**
* Gets the parameter of kind `kind` of a Connect/Express route parameter handler function.
*
* `kind` is one of: "error", "request", "response", "next".
*/
pragma[inline]
Parameter getRouteParameterHandlerParameter(Function routeHandler, string kind) {
result =
getRouteHandlerParameter(routeHandler, RouteHandlerSignature::requestResponseNextParameter(),
kind)
}
/**
* Gets the parameter of kind `kind` of a Connect/Express route handler function.
*
* `kind` is one of: "error", "request", "response", "next".
*/
SimpleParameter getRouteHandlerParameter(Function routeHandler, string kind) {
exists(int index, int offset |
result = routeHandler.getParameter(index + offset) and
(if routeHandler.getNumParameter() = 4 then offset = 0 else offset = -1)
|
kind = "error" and index = 0
or
kind = "request" and index = 1
or
kind = "response" and index = 2
or
kind = "next" and index = 3
)
pragma[inline]
Parameter getRouteHandlerParameter(Function routeHandler, string kind) {
if routeHandler.getNumParameter() = 4
then
// For arity 4 there is ambiguity between (err, req, res, next) and (req, res, next, param)
// This predicate favors the 'err' signature whereas getRouteParameterHandlerParameter favors the other.
result =
getRouteHandlerParameter(routeHandler, RouteHandlerSignature::errorRequestResponseNext(),
kind)
else
result =
getRouteHandlerParameter(routeHandler, RouteHandlerSignature::requestResponseNext(), kind)
}
/**
@@ -34,39 +114,16 @@ module ConnectExpressShared {
*/
class RouteHandlerCandidate extends HTTP::RouteHandlerCandidate {
RouteHandlerCandidate() {
exists(string request, string response, string next, string error |
(request = "request" or request = "req") and
(response = "response" or response = "res") and
next = "next" and
(error = "error" or error = "err")
|
// heuristic: parameter names match the documentation
astNode.getNumParameter() >= 2 and
getRouteHandlerParameter(astNode, "request").getName() = request and
getRouteHandlerParameter(astNode, "response").getName() = response and
(
astNode.getNumParameter() >= 3
implies
getRouteHandlerParameter(astNode, "next").getName() = next
) and
(
astNode.getNumParameter() = 4
implies
getRouteHandlerParameter(astNode, "error").getName() = error
) and
not (
// heuristic: max four parameters (the server will only supply four arguments)
astNode.getNumParameter() > 4
or
// heuristic: not a class method (the server invokes this with a function call)
astNode = any(MethodDefinition def).getBody()
or
// heuristic: does not return anything (the server will not use the return value)
exists(astNode.getAReturnStmt().getExpr())
or
// heuristic: is not invoked (the server invokes this at a call site we cannot reason precisely about)
exists(DataFlow::InvokeNode cs | cs.getACallee() = astNode)
)
matchesSignature(astNode, _) and
not (
// heuristic: not a class method (the server invokes this with a function call)
astNode = any(MethodDefinition def).getBody()
or
// heuristic: does not return anything (the server will not use the return value)
exists(astNode.getAReturnStmt().getExpr())
or
// heuristic: is not invoked (the server invokes this at a call site we cannot reason precisely about)
exists(DataFlow::InvokeNode cs | cs.getACallee() = astNode)
)
}
}

View File

@@ -127,14 +127,14 @@ module Express {
/**
* Gets the HTTP request type this is registered for, if any.
*
* Has no result for `use` and `all` calls.
* Has no result for `use`, `all`, or `param` calls.
*/
HTTP::RequestMethodName getRequestMethod() { result.toLowerCase() = getMethodName() }
/**
* Holds if this registers a route for all request methods.
*/
predicate handlesAllRequestMethods() { getMethodName() = "use" or getMethodName() = "all" }
predicate handlesAllRequestMethods() { getMethodName() = ["use", "all", "param"] }
/**
* Holds if this route setup sets up a route for the same
@@ -146,6 +146,11 @@ module Express {
that.handlesAllRequestMethods() or
this.getRequestMethod() = that.getRequestMethod()
}
/**
* Holds if this route setup is a parameter handler, such as `app.param("foo", ...)`.
*/
predicate isParameterHandler() { getMethodName() = "param" }
}
/**
@@ -314,7 +319,7 @@ module Express {
/**
* Gets the parameter of kind `kind` of this route handler.
*
* `kind` is one of: "error", "request", "response", "next".
* `kind` is one of: "error", "request", "response", "next", or "parameter".
*/
abstract SimpleParameter getRouteHandlerParameter(string kind);
@@ -340,11 +345,14 @@ module Express {
class StandardRouteHandler extends RouteHandler, HTTP::Servers::StandardRouteHandler,
DataFlow::ValueNode {
override Function astNode;
RouteSetup routeSetup;
StandardRouteHandler() { this = any(RouteSetup setup).getARouteHandler() }
StandardRouteHandler() { this = routeSetup.getARouteHandler() }
override SimpleParameter getRouteHandlerParameter(string kind) {
result = getRouteHandlerParameter(astNode, kind)
if routeSetup.isParameterHandler()
then result = getRouteParameterHandlerParameter(astNode, kind)
else result = getRouteHandlerParameter(astNode, kind)
}
}
@@ -453,32 +461,31 @@ module Express {
string kind;
RequestInputAccess() {
exists(DataFlow::Node request | request = DataFlow::valueNode(rh.getARequestExpr()) |
exists(DataFlow::SourceNode request | request = rh.getARequestSource().ref() |
kind = "parameter" and
(
this.(DataFlow::MethodCallNode).calls(request, "param")
this = request.getAMethodCall("param")
or
exists(DataFlow::PropRead base, string propName |
// `req.params.name` or `req.query.name`
base.accesses(request, propName) and
this = base.getAPropertyReference(_)
|
propName = "params" or
propName = "query"
)
this = request.getAPropertyRead(["params", "query"]).getAPropertyRead()
)
or
// `req.originalUrl`
kind = "url" and
this.(DataFlow::PropRef).accesses(request, "originalUrl")
this = request.getAPropertyRead("originalUrl")
or
// `req.cookies`
kind = "cookie" and
this.(DataFlow::PropRef).accesses(request, "cookies")
this = request.getAPropertyRead("cookies")
)
or
kind = "body" and
this.asExpr() = rh.getARequestBodyAccess()
or
// `value` in `router.param('foo', (req, res, next, value) => { ... })`
kind = "parameter" and
exists(RouteSetup setup | rh = setup.getARouteHandler() |
this = DataFlow::parameterNode(rh.getRouteHandlerParameter("parameter"))
)
}
override RouteHandler getRouteHandler() { result = rh }
@@ -848,10 +855,14 @@ module Express {
*/
private class TrackedRouteHandlerCandidateWithSetup extends RouteHandler,
HTTP::Servers::StandardRouteHandler, DataFlow::FunctionNode {
TrackedRouteHandlerCandidateWithSetup() { this = any(RouteSetup s).getARouteHandler() }
RouteSetup routeSetup;
TrackedRouteHandlerCandidateWithSetup() { this = routeSetup.getARouteHandler() }
override SimpleParameter getRouteHandlerParameter(string kind) {
result = getRouteHandlerParameter(astNode, kind)
if routeSetup.isParameterHandler()
then result = getRouteParameterHandlerParameter(astNode, kind)
else result = getRouteHandlerParameter(astNode, kind)
}
}

View File

@@ -219,12 +219,14 @@ module Firebase {
*/
private class RouteHandler extends Express::RouteHandler, HTTP::Servers::StandardRouteHandler,
DataFlow::ValueNode {
override Function astNode;
RouteHandler() { this = any(RouteSetup setup).getARouteHandler() }
override SimpleParameter getRouteHandlerParameter(string kind) {
kind = "request" and result = this.(DataFlow::FunctionNode).getParameter(0).getParameter()
kind = "request" and result = astNode.getParameter(0)
or
kind = "response" and result = this.(DataFlow::FunctionNode).getParameter(1).getParameter()
kind = "response" and result = astNode.getParameter(1)
}
}
}

View File

@@ -204,6 +204,20 @@ module HTTP {
*/
abstract HeaderDefinition getAResponseHeader(string name);
/**
* Gets a request object originating from this route handler.
*
* Use `RequestSource.ref()` to get reference to this request object.
*/
final Servers::RequestSource getARequestSource() { result.getRouteHandler() = this }
/**
* Gets a response object originating from this route handler.
*
* Use `ResponseSource.ref()` to get reference to this response object.
*/
final Servers::ResponseSource getAResponseSource() { result.getRouteHandler() = this }
/**
* Gets an expression that contains a request object handled
* by this handler.
@@ -296,7 +310,8 @@ module HTTP {
*/
abstract RouteHandler getRouteHandler();
predicate flowsTo(DataFlow::Node nd) { ref(DataFlow::TypeTracker::end()).flowsTo(nd) }
/** DEPRECATED. Use `ref().flowsTo()` instead. */
deprecated predicate flowsTo(DataFlow::Node nd) { ref().flowsTo(nd) }
private DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
t.start() and
@@ -304,6 +319,9 @@ module HTTP {
or
exists(DataFlow::TypeTracker t2 | result = ref(t2).track(t2, t))
}
/** Gets a `SourceNode` that refers to this request object. */
DataFlow::SourceNode ref() { result = ref(DataFlow::TypeTracker::end()) }
}
/**
@@ -317,7 +335,8 @@ module HTTP {
*/
abstract RouteHandler getRouteHandler();
predicate flowsTo(DataFlow::Node nd) { ref(DataFlow::TypeTracker::end()).flowsTo(nd) }
/** DEPRECATED. Use `ref().flowsTo()` instead. */
deprecated predicate flowsTo(DataFlow::Node nd) { ref().flowsTo(nd) }
private DataFlow::SourceNode ref(DataFlow::TypeTracker t) {
t.start() and
@@ -325,6 +344,9 @@ module HTTP {
or
exists(DataFlow::TypeTracker t2 | result = ref(t2).track(t2, t))
}
/** Gets a `SourceNode` that refers to this response object. */
DataFlow::SourceNode ref() { result = ref(DataFlow::TypeTracker::end()) }
}
/**
@@ -333,7 +355,7 @@ module HTTP {
class StandardRequestExpr extends RequestExpr {
RequestSource src;
StandardRequestExpr() { src.flowsTo(DataFlow::valueNode(this)) }
StandardRequestExpr() { src.ref().flowsTo(DataFlow::valueNode(this)) }
override RouteHandler getRouteHandler() { result = src.getRouteHandler() }
}
@@ -344,7 +366,7 @@ module HTTP {
class StandardResponseExpr extends ResponseExpr {
ResponseSource src;
StandardResponseExpr() { src.flowsTo(DataFlow::valueNode(this)) }
StandardResponseExpr() { src.ref().flowsTo(DataFlow::valueNode(this)) }
override RouteHandler getRouteHandler() { result = src.getRouteHandler() }
}
@@ -370,6 +392,7 @@ module HTTP {
/**
* Gets a route handler that is defined by this setup.
*/
pragma[nomagic]
abstract DataFlow::SourceNode getARouteHandler();
/**

View File

@@ -74,7 +74,7 @@ module LazyCache {
}
/** A constant path element appearing in a call to a lazy-cache object. */
private class LazyCachePathExpr extends PathExprInModule, ConstantString {
private class LazyCachePathExpr extends PathExpr, ConstantString {
LazyCachePathExpr() { this = any(LazyCacheImport rp).getArgument(0) }
override string getValue() { result = getStringValue() }

View File

@@ -306,7 +306,7 @@ module NodeJSLib {
FsFlowTarget() {
exists(DataFlow::CallNode call, string methodName |
call = DataFlow::moduleMember("fs", methodName).getACall()
call = FS::moduleMember(methodName).getACall()
|
methodName = "realpathSync" and
tainted = call.getArgument(0) and
@@ -430,27 +430,32 @@ module NodeJSLib {
}
/**
* A member `member` from module `fs` or its drop-in replacements `graceful-fs`, `fs-extra`, `original-fs`.
* Provides predicates for working with the "fs" module and its variants as a single module.
*/
private DataFlow::SourceNode fsModuleMember(string member) {
result = fsModule(DataFlow::TypeTracker::end()).getAPropertyRead(member)
}
module FS {
/**
* A member `member` from module `fs` or its drop-in replacements `graceful-fs`, `fs-extra`, `original-fs`.
*/
DataFlow::SourceNode moduleMember(string member) {
result = fsModule(DataFlow::TypeTracker::end()).getAPropertyRead(member)
}
private DataFlow::SourceNode fsModule(DataFlow::TypeTracker t) {
exists(string moduleName |
moduleName = "fs" or
moduleName = "graceful-fs" or
moduleName = "fs-extra" or
moduleName = "original-fs"
|
result = DataFlow::moduleImport(moduleName)
private DataFlow::SourceNode fsModule(DataFlow::TypeTracker t) {
exists(string moduleName |
moduleName = "fs" or
moduleName = "graceful-fs" or
moduleName = "fs-extra" or
moduleName = "original-fs"
|
result = DataFlow::moduleImport(moduleName)
or
// extra support for flexible names
result.asExpr().(Require).getArgument(0).mayHaveStringValue(moduleName)
) and
t.start()
or
// extra support for flexible names
result.asExpr().(Require).getArgument(0).mayHaveStringValue(moduleName)
) and
t.start()
or
exists(DataFlow::TypeTracker t2 | result = fsModule(t2).track(t2, t))
exists(DataFlow::TypeTracker t2 | result = fsModule(t2).track(t2, t))
}
}
/**
@@ -459,7 +464,7 @@ module NodeJSLib {
private class NodeJSFileSystemAccess extends FileSystemAccess, DataFlow::CallNode {
string methodName;
NodeJSFileSystemAccess() { this = maybePromisified(fsModuleMember(methodName)).getACall() }
NodeJSFileSystemAccess() { this = maybePromisified(FS::moduleMember(methodName)).getACall() }
/**
* Gets the name of the called method.
@@ -479,7 +484,9 @@ module NodeJSLib {
methodName = "write" or
methodName = "writeFile" or
methodName = "writeFileSync" or
methodName = "writeSync"
methodName = "writeSync" or
methodName = "link" or
methodName = "linkSync"
}
override DataFlow::Node getADataNode() {
@@ -580,8 +587,8 @@ module NodeJSLib {
name = "readdir" or
name = "realpath"
|
this = fsModuleMember(name).getACall().getCallback([1 .. 2]).getParameter(1) or
this = fsModuleMember(name + "Sync").getACall()
this = FS::moduleMember(name).getACall().getCallback([1 .. 2]).getParameter(1) or
this = FS::moduleMember(name + "Sync").getACall()
)
}
}

View File

@@ -590,7 +590,7 @@ module JQuery {
// Handle basic dynamic method dispatch (e.g. `$element[html ? 'html' : 'text'](content)`)
exists(DataFlow::PropRead read | read = this.getCalleeNode() |
read.getBase().getALocalSource() = [dollar(), objectRef()] and
read.getPropertyNameExpr().flow().mayHaveStringValue(name)
read.mayHavePropertyName(name)
)
or
// Handle contributed JQuery objects that aren't source nodes (usually parameter uses)
@@ -654,10 +654,7 @@ module JQuery {
)
) and
plugin = write.getRhs() and
(
pluginName = write.getPropertyName() or
write.getPropertyNameExpr().flow().mayHaveStringValue(pluginName)
)
write.mayHavePropertyName(pluginName)
)
}

View File

@@ -9,6 +9,8 @@ import semmle.javascript.security.dataflow.RemoteFlowSources
import UrlConcatenation
module ClientSideUrlRedirect {
private import Xss::DomBasedXss as DomBasedXss
/**
* A data flow source for unvalidated URL redirect vulnerabilities.
*/
@@ -52,7 +54,7 @@ module ClientSideUrlRedirect {
mce = queryAccess.asExpr() and mce.calls(nd.asExpr(), methodName)
|
methodName = "split" and
// exclude `location.href.split('?')[0]`, which can never refer to the query string
// exclude all splits where only the prefix is accessed, which is safe for url-redirects.
not exists(PropAccess pacc | mce = pacc.getBase() | pacc.getPropertyName() = "0")
or
(methodName = "substring" or methodName = "substr" or methodName = "slice") and
@@ -68,6 +70,11 @@ module ClientSideUrlRedirect {
)
}
/**
* A sanitizer that reads the first part a location split by "?", e.g. `location.href.split('?')[0]`.
*/
class QueryPrefixSanitizer extends Sanitizer, DomBasedXss::QueryPrefixSanitizer { }
/**
* A sink which is used to set the window location.
*/

View File

@@ -97,23 +97,17 @@ module TaintedPath {
)
)
or
// A `str.split()` call can either split into path elements (`str.split("/")`) or split by some other string.
exists(StringSplitCall mcn | dst = mcn and mcn.getBaseString() = src |
if mcn.getSeparator() = "/"
then
srclabel.(Label::PosixPath).canContainDotDotSlash() and
dstlabel instanceof Label::SplitPath
else srclabel = dstlabel
)
or
// array method calls of interest
exists(DataFlow::MethodCallNode mcn, string name | dst = mcn and mcn.calls(src, name) |
// A `str.split()` call can either split into path elements (`str.split("/")`) or split by some other string.
name = "split" and
(
if
exists(DataFlow::Node splitBy | splitBy = mcn.getArgument(0) |
splitBy.mayHaveStringValue("/") or
any(DataFlow::RegExpCreationNode reg | reg.getRoot().getAMatchedString() = "/")
.flowsTo(splitBy)
)
then
srclabel.(Label::PosixPath).canContainDotDotSlash() and
dstlabel instanceof Label::SplitPath
else srclabel = dstlabel
)
or
(
name = "pop" or
name = "shift"

View File

@@ -155,11 +155,11 @@ module TaintedPath {
input = getAnArgument() and
output = this
or
this = DataFlow::moduleMember("fs", "realpathSync").getACall() and
this = NodeJSLib::FS::moduleMember("realpathSync").getACall() and
input = getArgument(0) and
output = this
or
this = DataFlow::moduleMember("fs", "realpath").getACall() and
this = NodeJSLib::FS::moduleMember("realpath").getACall() and
input = getArgument(0) and
output = getCallback(1).getParameter(1)
}

View File

@@ -278,6 +278,20 @@ module DomBasedXss {
}
}
/**
* A sanitizer that reads the first part a location split by "?", e.g. `location.href.split('?')[0]`.
*/
class QueryPrefixSanitizer extends Sanitizer {
StringSplitCall splitCall;
QueryPrefixSanitizer() {
this = splitCall.getASubstringRead(0) and
splitCall.getSeparator() = "?" and
splitCall.getBaseString().getALocalSource() =
[DOM::locationRef(), DOM::locationRef().getAPropertyRead("href")]
}
}
/**
* A regexp replacement involving an HTML meta-character, viewed as a sanitizer for
* XSS vulnerabilities.

View File

@@ -81,10 +81,7 @@ module XssThroughDom {
DOMTextSource() {
exists(DataFlow::PropRead read | read = this |
read.getBase().getALocalSource() = DOM::domValueRef() and
exists(string propName | propName = ["innerText", "textContent", "value", "name"] |
read.getPropertyName() = propName or
read.getPropertyNameExpr().flow().mayHaveStringValue(propName)
)
read.mayHavePropertyName(["innerText", "textContent", "value", "name"])
)
or
exists(DataFlow::MethodCallNode mcn | mcn = this |

View File

@@ -47,11 +47,13 @@ module ZipSlip {
)
}
/** Gets a property that is used to get the filename part of an archive entry. */
/** Gets a property that is used to get a filename part of an archive entry. */
private string getAFilenameProperty() {
result = "path" // Used by library 'unzip'.
or
result = "name" // Used by library 'tar-stream'.
or
result = "linkname" // linked file name, used by 'tar-stream'.
}
/** An archive entry path access, as a source for unsafe archive extraction. */
@@ -105,7 +107,14 @@ module ZipSlip {
// However, we want to consider even the bare `createWriteStream`
// to be a zipslip vulnerability since it may truncate an
// existing file.
this = DataFlow::moduleImport("fs").getAMemberCall("createWriteStream").getArgument(0)
this = NodeJSLib::FS::moduleMember("createWriteStream").getACall().getArgument(0)
or
// Not covered by `FileSystemWriteSink` because a later call
// to `fs.write` is required for a write to take place.
exists(DataFlow::CallNode call | this = call.getArgument(0) |
call = NodeJSLib::FS::moduleMember(["open", "openSync"]).getACall() and
call.getArgument(1).getStringValue().regexpMatch("(?i)w.{0,2}")
)
}
}
@@ -119,6 +128,20 @@ module ZipSlip {
BasenameSanitizer() { this = DataFlow::moduleImport("path").getAMemberCall("basename") }
}
/**
* An expression that forces the output path to be in the current working folder.
* Recognizes the pattern: `path.join(cwd, path.join('/', orgPath))`.
*/
class PathSanitizer extends Sanitizer, DataFlow::CallNode {
PathSanitizer() {
this = NodeJSLib::Path::moduleMember("join").getACall() and
exists(DataFlow::CallNode inner | inner = getArgument(1) |
inner = NodeJSLib::Path::moduleMember("join").getACall() and
inner.getArgument(0).mayHaveStringValue("/")
)
}
}
/**
* Gets a string which is sufficient to exclude to make
* a filepath definitely not refer to parent directories.

View File

@@ -22,7 +22,7 @@ query predicate test_ImportNamespaceSpecifier(ImportNamespaceSpecifier ins) { an
query predicate test_ImportSpecifiers(ImportSpecifier is, VarDecl res) { res = is.getLocal() }
query predicate test_Imports(ImportDeclaration id, PathExprInModule res0, int res1) {
query predicate test_Imports(ImportDeclaration id, PathExpr res0, int res1) {
res0 = id.getImportedPath() and res1 = count(id.getASpecifier())
}

View File

@@ -3,4 +3,7 @@ var app = express();
app.get('/some/path', function(req, res) {
let { foo, bar: baz } = req.query;
let dynamic1 = req.query[foo];
let dynamic2 = req.query[something()];
res.send(dynamic1);
});

View File

@@ -0,0 +1,16 @@
var express = require('express');
var app = express();
app.param('foo', (req, res, next, value) => {
console.log(req.query.xx);
console.log(req.body.xx);
if (value) {
res.send(value);
} else {
next();
}
});
app.get('/hello/:foo', function(req, res) {
res.send("Hello");
});

View File

@@ -7,12 +7,14 @@ test_RouteHandlerExpr_getBody
| src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:3:25:3:55 | functio ... , res } |
| src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:32:4:76 | functio ... esult } |
| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express4.js:4:23:6:1 | functio ... uery;\\n} | src/express4.js:4:23:6:1 | functio ... uery;\\n} |
| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:23:9:1 | functio ... res);\\n} |
| src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:16:19:18:3 | functio ... ");\\n } |
| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:30:32:1 | functio ... ar');\\n} |
| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:22:51:1 | functio ... ame];\\n} |
| src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} |
| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:14:24:16:1 | functio ... lo");\\n} |
| src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} |
| src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} |
| src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} |
@@ -28,12 +30,14 @@ test_RouteSetup
| src/express2.js:3:1:3:56 | router. ... res }) | src/express2.js:5:11:5:13 | e() | false |
| src/express2.js:3:1:4:77 | router. ... sult }) | src/express2.js:5:11:5:13 | e() | false |
| src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:2:11:2:19 | express() | false |
| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | src/express4.js:2:11:2:19 | express() | false |
| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:2:11:2:19 | express() | false |
| src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() | false |
| src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:2:11:2:19 | express() | false |
| src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() | false |
| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() | false |
| src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() | false |
| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() | false |
| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() | false |
| src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() | false |
| src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() | false |
| src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() | false |
@@ -55,7 +59,7 @@ test_RouteSetup_getLastRouteHandlerExpr
| src/express2.js:6:1:6:15 | app.use(router) | src/express2.js:6:9:6:14 | router |
| src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express3.js:12:1:12:21 | app.use ... dler()) | src/express3.js:12:9:12:20 | getHandler() |
| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | src/express4.js:4:23:6:1 | functio ... uery;\\n} |
| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:4:23:9:1 | functio ... res);\\n} |
| src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:16:19:18:3 | functio ... ");\\n } |
| src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:22:30:32:1 | functio ... ar');\\n} |
@@ -64,6 +68,8 @@ test_RouteSetup_getLastRouteHandlerExpr
| src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:44:9:44:25 | getArrowHandler() |
| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:46:22:51:1 | functio ... ame];\\n} |
| src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} |
| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:14:24:16:1 | functio ... lo");\\n} |
| src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} |
| src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} |
| src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} |
@@ -182,6 +188,8 @@ test_isRequest
| src/express3.js:5:14:5:16 | req |
| src/express3.js:5:35:5:37 | req |
| src/express4.js:5:27:5:29 | req |
| src/express4.js:6:18:6:20 | req |
| src/express4.js:7:18:7:20 | req |
| src/express.js:5:16:5:18 | req |
| src/express.js:6:26:6:28 | req |
| src/express.js:23:3:23:5 | req |
@@ -197,6 +205,8 @@ test_isRequest
| src/express.js:49:3:49:5 | req |
| src/express.js:50:3:50:5 | req |
| src/inheritedFromNode.js:7:2:7:4 | req |
| src/params.js:5:17:5:19 | req |
| src/params.js:6:17:6:19 | req |
| src/passport.js:28:2:28:4 | req |
| src/responseExprs.js:17:5:17:7 | req |
test_RouteSetup_getRouter
@@ -215,7 +225,7 @@ test_RouteSetup_getRouter
| src/express2.js:6:1:6:15 | app.use(router) | src/express2.js:5:11:5:13 | e() |
| src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:2:11:2:19 | express() |
| src/express3.js:12:1:12:21 | app.use ... dler()) | src/express3.js:2:11:2:19 | express() |
| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | src/express4.js:2:11:2:19 | express() |
| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:2:11:2:19 | express() |
| src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() |
| src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:2:11:2:19 | express() |
| src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() |
@@ -224,6 +234,8 @@ test_RouteSetup_getRouter
| src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:2:11:2:19 | express() |
| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() |
| src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() |
| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() |
| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() |
| src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() |
| src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() |
| src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() |
@@ -249,12 +261,14 @@ test_StandardRouteHandler
| src/express2.js:3:25:3:55 | functio ... , res } | src/express2.js:5:11:5:13 | e() | src/express2.js:3:34:3:36 | req | src/express2.js:3:39:3:41 | res |
| src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:5:11:5:13 | e() | src/express2.js:4:41:4:47 | request | src/express2.js:4:50:4:55 | result |
| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:2:11:2:19 | express() | src/express3.js:4:32:4:34 | req | src/express3.js:4:37:4:39 | res |
| src/express4.js:4:23:6:1 | functio ... uery;\\n} | src/express4.js:2:11:2:19 | express() | src/express4.js:4:32:4:34 | req | src/express4.js:4:37:4:39 | res |
| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:2:11:2:19 | express() | src/express4.js:4:32:4:34 | req | src/express4.js:4:37:4:39 | res |
| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:2:11:2:19 | express() | src/express.js:4:32:4:34 | req | src/express.js:4:37:4:39 | res |
| src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:2:11:2:19 | express() | src/express.js:16:28:16:30 | req | src/express.js:16:33:16:35 | res |
| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:2:11:2:19 | express() | src/express.js:22:39:22:41 | req | src/express.js:22:44:22:46 | res |
| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:2:11:2:19 | express() | src/express.js:46:31:46:33 | req | src/express.js:46:36:46:38 | res |
| src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:2:11:2:19 | express() | src/inheritedFromNode.js:4:24:4:26 | req | src/inheritedFromNode.js:4:29:4:31 | res |
| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:2:11:2:19 | express() | src/params.js:4:19:4:21 | req | src/params.js:4:24:4:26 | res |
| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:2:11:2:19 | express() | src/params.js:14:33:14:35 | req | src/params.js:14:38:14:40 | res |
| src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:4:32:4:34 | req | src/responseExprs.js:4:37:4:40 | res1 |
| src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:7:32:7:34 | req | src/responseExprs.js:7:37:7:40 | res2 |
| src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:10:39:10:41 | req | src/responseExprs.js:10:44:10:47 | res3 |
@@ -263,8 +277,10 @@ test_StandardRouteHandler
test_RequestInputAccess
| src/express3.js:5:14:5:32 | req.param("header") | parameter | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express3.js:5:35:5:50 | req.param("val") | parameter | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express4.js:5:9:5:11 | foo | parameter | src/express4.js:4:23:6:1 | functio ... uery;\\n} |
| src/express4.js:5:14:5:21 | bar: baz | parameter | src/express4.js:4:23:6:1 | functio ... uery;\\n} |
| src/express4.js:5:9:5:11 | foo | parameter | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express4.js:5:14:5:21 | bar: baz | parameter | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express4.js:6:18:6:31 | req.query[foo] | parameter | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express4.js:7:18:7:39 | req.que ... hing()] | parameter | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express.js:5:16:5:34 | req.param("target") | parameter | src/express.js:4:23:9:1 | functio ... res);\\n} |
| src/express.js:6:26:6:44 | req.param("target") | parameter | src/express.js:4:23:9:1 | functio ... res);\\n} |
| src/express.js:23:3:23:10 | req.body | body | src/express.js:22:30:32:1 | functio ... ar');\\n} |
@@ -280,6 +296,9 @@ test_RequestInputAccess
| src/express.js:49:3:49:14 | req.hostname | header | src/express.js:46:22:51:1 | functio ... ame];\\n} |
| src/express.js:50:3:50:32 | req.hea ... erName] | header | src/express.js:46:22:51:1 | functio ... ame];\\n} |
| src/inheritedFromNode.js:7:2:7:8 | req.url | url | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} |
| src/params.js:4:35:4:39 | value | parameter | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/params.js:5:17:5:28 | req.query.xx | parameter | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/params.js:6:17:6:24 | req.body | body | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/passport.js:28:2:28:9 | req.body | body | src/passport.js:27:4:29:1 | functio ... ccss`\\n} |
test_SetCookie
| src/express.js:31:3:31:26 | res.coo ... 'bar') | src/express.js:22:30:32:1 | functio ... ar');\\n} |
@@ -335,6 +354,8 @@ test_ResponseExpr
| src/express3.js:5:3:5:51 | res.hea ... "val")) | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express3.js:6:3:6:5 | res | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express3.js:6:3:6:17 | res.send("val") | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express4.js:8:3:8:5 | res | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express4.js:8:3:8:20 | res.send(dynamic1) | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express.js:5:3:5:5 | res | src/express.js:4:23:9:1 | functio ... res);\\n} |
| src/express.js:6:3:6:5 | res | src/express.js:4:23:9:1 | functio ... res);\\n} |
| src/express.js:6:3:6:45 | res.hea ... rget")) | src/express.js:4:23:9:1 | functio ... res);\\n} |
@@ -349,6 +370,10 @@ test_ResponseExpr
| src/express.js:31:3:31:26 | res.coo ... 'bar') | src/express.js:22:30:32:1 | functio ... ar');\\n} |
| src/inheritedFromNode.js:5:2:5:4 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} |
| src/inheritedFromNode.js:6:2:6:4 | res | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} |
| src/params.js:8:9:8:11 | res | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/params.js:8:9:8:23 | res.send(value) | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/params.js:15:3:15:5 | res | src/params.js:14:24:16:1 | functio ... lo");\\n} |
| src/params.js:15:3:15:19 | res.send("Hello") | src/params.js:14:24:16:1 | functio ... lo");\\n} |
| src/responseExprs.js:5:5:5:8 | res1 | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} |
| src/responseExprs.js:8:5:8:8 | res2 | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} |
| src/responseExprs.js:11:5:11:8 | res3 | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} |
@@ -401,12 +426,14 @@ test_RouterDefinition_getARouteHandler
| src/express2.js:2:14:2:23 | e.Router() | src/express2.js:3:25:3:55 | functio ... , res } |
| src/express2.js:2:14:2:23 | e.Router() | src/express2.js:4:32:4:76 | functio ... esult } |
| src/express3.js:2:11:2:19 | express() | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express4.js:2:11:2:19 | express() | src/express4.js:4:23:6:1 | functio ... uery;\\n} |
| src/express4.js:2:11:2:19 | express() | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express.js:2:11:2:19 | express() | src/express.js:4:23:9:1 | functio ... res);\\n} |
| src/express.js:2:11:2:19 | express() | src/express.js:16:19:18:3 | functio ... ");\\n } |
| src/express.js:2:11:2:19 | express() | src/express.js:22:30:32:1 | functio ... ar');\\n} |
| src/express.js:2:11:2:19 | express() | src/express.js:46:22:51:1 | functio ... ame];\\n} |
| src/inheritedFromNode.js:2:11:2:19 | express() | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} |
| src/params.js:2:11:2:19 | express() | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/params.js:2:11:2:19 | express() | src/params.js:14:24:16:1 | functio ... lo");\\n} |
| src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} |
| src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} |
| src/responseExprs.js:2:11:2:19 | express() | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} |
@@ -450,6 +477,7 @@ test_ExpressSession
| src/express-session.js:7:1:9:2 | session ... -3"]\\n}) | secret | src/express-session.js:8:13:8:44 | ["secre ... key-3"] |
test_RequestBodyAccess
| src/express.js:23:3:23:10 | req.body |
| src/params.js:6:17:6:24 | req.body |
| src/passport.js:28:2:28:9 | req.body |
test_RouteSetup_getServer
| src/csurf-example.js:20:1:23:2 | app.get ... ) })\\n}) | src/csurf-example.js:7:11:7:19 | express() |
@@ -460,12 +488,14 @@ test_RouteSetup_getServer
| src/express2.js:3:1:3:56 | router. ... res }) | src/express2.js:5:11:5:13 | e() |
| src/express2.js:3:1:4:77 | router. ... sult }) | src/express2.js:5:11:5:13 | e() |
| src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:2:11:2:19 | express() |
| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | src/express4.js:2:11:2:19 | express() |
| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:2:11:2:19 | express() |
| src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() |
| src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:2:11:2:19 | express() |
| src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() |
| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() |
| src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() |
| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() |
| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() |
| src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() |
| src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() |
| src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() |
@@ -497,7 +527,7 @@ test_RouteHandlerExpr
| src/express2.js:6:9:6:14 | router | src/express2.js:6:1:6:15 | app.use(router) | false |
| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:1:7:2 | app.get ... l");\\n}) | true |
| src/express3.js:12:9:12:20 | getHandler() | src/express3.js:12:1:12:21 | app.use ... dler()) | false |
| src/express4.js:4:23:6:1 | functio ... uery;\\n} | src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | true |
| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | true |
| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:1:9:2 | app.get ... es);\\n}) | true |
| src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:16:3:18:4 | router. ... );\\n }) | true |
| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:1:32:2 | app.pos ... r');\\n}) | true |
@@ -506,6 +536,8 @@ test_RouteHandlerExpr
| src/express.js:44:9:44:25 | getArrowHandler() | src/express.js:44:1:44:26 | app.use ... dler()) | false |
| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:1:51:2 | app.pos ... me];\\n}) | true |
| src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | true |
| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:4:1:12:2 | app.par ... }\\n}) | true |
| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:14:1:16:2 | app.get ... o");\\n}) | true |
| src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | true |
| src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | true |
| src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | true |
@@ -530,7 +562,9 @@ test_RouteSetup_handlesAllRequestMethods
| src/express3.js:12:1:12:21 | app.use ... dler()) |
| src/express.js:39:1:39:21 | app.use ... dler()) |
| src/express.js:44:1:44:26 | app.use ... dler()) |
| src/params.js:4:1:12:2 | app.par ... }\\n}) |
| src/route.js:4:1:5:39 | router. ... xt) {}) |
| src/routesetups.js:3:1:4:14 | express ... ('', h) |
| src/subrouter.js:4:1:4:26 | app.use ... rotect) |
| src/subrouter.js:5:1:5:29 | app.use ... uter()) |
test_RouterDefinition_getASubRouter
@@ -550,6 +584,7 @@ test_appCreation
| src/express4.js:2:11:2:19 | express() |
| src/express.js:2:11:2:19 | express() |
| src/inheritedFromNode.js:2:11:2:19 | express() |
| src/params.js:2:11:2:19 | express() |
| src/responseExprs.js:2:11:2:19 | express() |
| src/routesetups.js:7:11:7:32 | express ... erver() |
| src/subrouter.js:2:11:2:19 | express() |
@@ -562,13 +597,14 @@ test_RouteSetup_getRequestMethod
| src/express2.js:3:1:3:56 | router. ... res }) | GET |
| src/express2.js:3:1:4:77 | router. ... sult }) | POST |
| src/express3.js:4:1:7:2 | app.get ... l");\\n}) | GET |
| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | GET |
| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | GET |
| src/express.js:4:1:9:2 | app.get ... es);\\n}) | GET |
| src/express.js:16:3:18:4 | router. ... );\\n }) | GET |
| src/express.js:22:1:32:2 | app.pos ... r');\\n}) | POST |
| src/express.js:34:1:34:53 | app.get ... andler) | GET |
| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | POST |
| src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | POST |
| src/params.js:14:1:16:2 | app.get ... o");\\n}) | GET |
| src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | GET |
| src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | GET |
| src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | GET |
@@ -595,7 +631,7 @@ test_RouteExpr
| src/express2.js:6:1:6:15 | app.use(router) | src/express2.js:5:11:5:13 | e() |
| src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:2:11:2:19 | express() |
| src/express3.js:12:1:12:21 | app.use ... dler()) | src/express3.js:2:11:2:19 | express() |
| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | src/express4.js:2:11:2:19 | express() |
| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:2:11:2:19 | express() |
| src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:2:11:2:19 | express() |
| src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:2:11:2:19 | express() |
| src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:2:11:2:19 | express() |
@@ -604,6 +640,8 @@ test_RouteExpr
| src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:2:11:2:19 | express() |
| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:2:11:2:19 | express() |
| src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:2:11:2:19 | express() |
| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:2:11:2:19 | express() |
| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:2:11:2:19 | express() |
| src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:2:11:2:19 | express() |
| src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:2:11:2:19 | express() |
| src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:2:11:2:19 | express() |
@@ -639,6 +677,8 @@ test_RouteHandler_getAResponseExpr
| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:3:5:51 | res.hea ... "val")) |
| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:6:3:6:5 | res |
| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:6:3:6:17 | res.send("val") |
| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:8:3:8:5 | res |
| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:8:3:8:20 | res.send(dynamic1) |
| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:5:3:5:5 | res |
| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:3:6:5 | res |
| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:3:6:45 | res.hea ... rget")) |
@@ -653,6 +693,10 @@ test_RouteHandler_getAResponseExpr
| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:31:3:31:26 | res.coo ... 'bar') |
| src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:5:2:5:4 | res |
| src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:6:2:6:4 | res |
| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:8:9:8:11 | res |
| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:8:9:8:23 | res.send(value) |
| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:15:3:15:5 | res |
| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:15:3:15:19 | res.send("Hello") |
| src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:5:5:5:8 | res1 |
| src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:8:5:8:8 | res2 |
| src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:11:5:11:8 | res3 |
@@ -710,6 +754,8 @@ test_isResponse
| src/express3.js:5:3:5:51 | res.hea ... "val")) |
| src/express3.js:6:3:6:5 | res |
| src/express3.js:6:3:6:17 | res.send("val") |
| src/express4.js:8:3:8:5 | res |
| src/express4.js:8:3:8:20 | res.send(dynamic1) |
| src/express.js:5:3:5:5 | res |
| src/express.js:6:3:6:5 | res |
| src/express.js:6:3:6:45 | res.hea ... rget")) |
@@ -724,6 +770,10 @@ test_isResponse
| src/express.js:31:3:31:26 | res.coo ... 'bar') |
| src/inheritedFromNode.js:5:2:5:4 | res |
| src/inheritedFromNode.js:6:2:6:4 | res |
| src/params.js:8:9:8:11 | res |
| src/params.js:8:9:8:23 | res.send(value) |
| src/params.js:15:3:15:5 | res |
| src/params.js:15:3:15:19 | res.send("Hello") |
| src/responseExprs.js:5:5:5:8 | res1 |
| src/responseExprs.js:8:5:8:8 | res2 |
| src/responseExprs.js:11:5:11:8 | res3 |
@@ -772,12 +822,18 @@ test_ResponseBody
| src/csurf-example.js:26:12:26:42 | 'csrf w ... t here' | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} |
| src/csurf-example.js:33:14:33:34 | 'no csr ... t here' | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } |
| src/express3.js:6:12:6:16 | "val" | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express4.js:8:12:8:19 | dynamic1 | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express.js:17:14:17:23 | "Go away." | src/express.js:16:19:18:3 | functio ... ");\\n } |
| src/params.js:8:18:8:22 | value | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/params.js:15:12:15:18 | "Hello" | src/params.js:14:24:16:1 | functio ... lo");\\n} |
test_ResponseSendArgument
| src/csurf-example.js:26:12:26:42 | 'csrf w ... t here' | src/csurf-example.js:25:22:27:1 | functio ... ere')\\n} |
| src/csurf-example.js:33:14:33:34 | 'no csr ... t here' | src/csurf-example.js:32:30:34:3 | functio ... e')\\n } |
| src/express3.js:6:12:6:16 | "val" | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express4.js:8:12:8:19 | dynamic1 | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express.js:17:14:17:23 | "Go away." | src/express.js:16:19:18:3 | functio ... ");\\n } |
| src/params.js:8:18:8:22 | value | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/params.js:15:12:15:18 | "Hello" | src/params.js:14:24:16:1 | functio ... lo");\\n} |
test_RouteSetup_getARouteHandler
| src/auth.js:4:1:4:53 | app.use ... d' }})) | src/auth.js:4:9:4:52 | basicAu ... rd' }}) |
| src/csurf-example.js:13:1:13:20 | app.use('/api', api) | src/csurf-example.js:10:11:10:27 | createApiRouter() |
@@ -796,7 +852,7 @@ test_RouteSetup_getARouteHandler
| src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express3.js:12:1:12:21 | app.use ... dler()) | src/express3.js:10:12:10:32 | functio ... res){} |
| src/express3.js:12:1:12:21 | app.use ... dler()) | src/express3.js:12:9:12:20 | getHandler() |
| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | src/express4.js:4:23:6:1 | functio ... uery;\\n} |
| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:4:23:9:1 | functio ... res);\\n} |
| src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:16:19:18:3 | functio ... ");\\n } |
| src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:22:30:32:1 | functio ... ar');\\n} |
@@ -808,6 +864,8 @@ test_RouteSetup_getARouteHandler
| src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:44:9:44:25 | getArrowHandler() |
| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:46:22:51:1 | functio ... ame];\\n} |
| src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} |
| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:14:24:16:1 | functio ... lo");\\n} |
| src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} |
| src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} |
| src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} |
@@ -855,6 +913,7 @@ test_isRouterCreation
| src/express4.js:2:11:2:19 | express() |
| src/express.js:2:11:2:19 | express() |
| src/inheritedFromNode.js:2:11:2:19 | express() |
| src/params.js:2:11:2:19 | express() |
| src/responseExprs.js:2:11:2:19 | express() |
| src/route.js:2:14:2:29 | express.Router() |
| src/routesetups.js:3:1:3:16 | express.Router() |
@@ -878,7 +937,7 @@ test_RouteSetup_getRouteHandlerExpr
| src/express2.js:6:1:6:15 | app.use(router) | 0 | src/express2.js:6:9:6:14 | router |
| src/express3.js:4:1:7:2 | app.get ... l");\\n}) | 0 | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express3.js:12:1:12:21 | app.use ... dler()) | 0 | src/express3.js:12:9:12:20 | getHandler() |
| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | 0 | src/express4.js:4:23:6:1 | functio ... uery;\\n} |
| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | 0 | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express.js:4:1:9:2 | app.get ... es);\\n}) | 0 | src/express.js:4:23:9:1 | functio ... res);\\n} |
| src/express.js:16:3:18:4 | router. ... );\\n }) | 0 | src/express.js:16:19:18:3 | functio ... ");\\n } |
| src/express.js:22:1:32:2 | app.pos ... r');\\n}) | 0 | src/express.js:22:30:32:1 | functio ... ar');\\n} |
@@ -887,6 +946,8 @@ test_RouteSetup_getRouteHandlerExpr
| src/express.js:44:1:44:26 | app.use ... dler()) | 0 | src/express.js:44:9:44:25 | getArrowHandler() |
| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | 0 | src/express.js:46:22:51:1 | functio ... ame];\\n} |
| src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | 0 | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} |
| src/params.js:4:1:12:2 | app.par ... }\\n}) | 0 | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/params.js:14:1:16:2 | app.get ... o");\\n}) | 0 | src/params.js:14:24:16:1 | functio ... lo");\\n} |
| src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | 0 | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} |
| src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | 0 | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} |
| src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | 0 | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} |
@@ -912,6 +973,7 @@ test_RouterDefinition_RouterDefinition
| src/express4.js:2:11:2:19 | express() |
| src/express.js:2:11:2:19 | express() |
| src/inheritedFromNode.js:2:11:2:19 | express() |
| src/params.js:2:11:2:19 | express() |
| src/responseExprs.js:2:11:2:19 | express() |
| src/route.js:2:14:2:29 | express.Router() |
| src/routesetups.js:3:1:3:16 | express.Router() |
@@ -921,6 +983,7 @@ test_RouterDefinition_RouterDefinition
| src/subrouter.js:8:16:8:31 | express.Router() |
test_RouteHandler_getARequestBodyAccess
| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:23:3:23:10 | req.body |
| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:6:17:6:24 | req.body |
| src/passport.js:27:4:29:1 | functio ... ccss`\\n} | src/passport.js:28:2:28:9 | req.body |
test_RouterDefinition_getMiddlewareStack
| src/auth.js:1:13:1:32 | require('express')() | src/auth.js:4:9:4:52 | basicAu ... rd' }}) |
@@ -940,7 +1003,7 @@ test_RouteHandler
| src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:41:4:47 | request | src/express2.js:4:50:4:55 | result |
| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:4:32:4:34 | req | src/express3.js:4:37:4:39 | res |
| src/express3.js:10:12:10:32 | functio ... res){} | src/express3.js:10:22:10:24 | req | src/express3.js:10:27:10:29 | res |
| src/express4.js:4:23:6:1 | functio ... uery;\\n} | src/express4.js:4:32:4:34 | req | src/express4.js:4:37:4:39 | res |
| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:4:32:4:34 | req | src/express4.js:4:37:4:39 | res |
| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:4:32:4:34 | req | src/express.js:4:37:4:39 | res |
| src/express.js:16:19:18:3 | functio ... ");\\n } | src/express.js:16:28:16:30 | req | src/express.js:16:33:16:35 | res |
| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:22:39:22:41 | req | src/express.js:22:44:22:46 | res |
@@ -948,6 +1011,8 @@ test_RouteHandler
| src/express.js:42:12:42:28 | (req, res) => f() | src/express.js:42:13:42:15 | req | src/express.js:42:18:42:20 | res |
| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:46:31:46:33 | req | src/express.js:46:36:46:38 | res |
| src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:4:24:4:26 | req | src/inheritedFromNode.js:4:29:4:31 | res |
| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:4:19:4:21 | req | src/params.js:4:24:4:26 | res |
| src/params.js:14:24:16:1 | functio ... lo");\\n} | src/params.js:14:33:14:35 | req | src/params.js:14:38:14:40 | res |
| src/responseExprs.js:4:23:6:1 | functio ... res1\\n} | src/responseExprs.js:4:32:4:34 | req | src/responseExprs.js:4:37:4:40 | res1 |
| src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} | src/responseExprs.js:7:32:7:34 | req | src/responseExprs.js:7:37:7:40 | res2 |
| src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} | src/responseExprs.js:10:39:10:41 | req | src/responseExprs.js:10:44:10:47 | res3 |
@@ -970,7 +1035,7 @@ test_RouteSetup_getARouteHandlerExpr
| src/express2.js:6:1:6:15 | app.use(router) | src/express2.js:6:9:6:14 | router |
| src/express3.js:4:1:7:2 | app.get ... l");\\n}) | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express3.js:12:1:12:21 | app.use ... dler()) | src/express3.js:12:9:12:20 | getHandler() |
| src/express4.js:4:1:6:2 | app.get ... ery;\\n}) | src/express4.js:4:23:6:1 | functio ... uery;\\n} |
| src/express4.js:4:1:9:2 | app.get ... c1);\\n}) | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express.js:4:1:9:2 | app.get ... es);\\n}) | src/express.js:4:23:9:1 | functio ... res);\\n} |
| src/express.js:16:3:18:4 | router. ... );\\n }) | src/express.js:16:19:18:3 | functio ... ");\\n } |
| src/express.js:22:1:32:2 | app.pos ... r');\\n}) | src/express.js:22:30:32:1 | functio ... ar');\\n} |
@@ -979,6 +1044,8 @@ test_RouteSetup_getARouteHandlerExpr
| src/express.js:44:1:44:26 | app.use ... dler()) | src/express.js:44:9:44:25 | getArrowHandler() |
| src/express.js:46:1:51:2 | app.pos ... me];\\n}) | src/express.js:46:22:51:1 | functio ... ame];\\n} |
| src/inheritedFromNode.js:4:1:8:2 | app.pos ... url;\\n}) | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} |
| src/params.js:4:1:12:2 | app.par ... }\\n}) | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/params.js:14:1:16:2 | app.get ... o");\\n}) | src/params.js:14:24:16:1 | functio ... lo");\\n} |
| src/responseExprs.js:4:1:6:2 | app.get ... res1\\n}) | src/responseExprs.js:4:23:6:1 | functio ... res1\\n} |
| src/responseExprs.js:7:1:9:2 | app.get ... es2;\\n}) | src/responseExprs.js:7:23:9:1 | functio ... res2;\\n} |
| src/responseExprs.js:10:1:12:2 | app.get ... es3;\\n}) | src/responseExprs.js:10:23:12:1 | functio ... res3;\\n} |
@@ -1011,7 +1078,9 @@ test_RequestExpr
| src/express2.js:4:60:4:66 | request | src/express2.js:4:32:4:76 | functio ... esult } |
| src/express3.js:5:14:5:16 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express3.js:5:35:5:37 | req | src/express3.js:4:23:7:1 | functio ... al");\\n} |
| src/express4.js:5:27:5:29 | req | src/express4.js:4:23:6:1 | functio ... uery;\\n} |
| src/express4.js:5:27:5:29 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express4.js:6:18:6:20 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express4.js:7:18:7:20 | req | src/express4.js:4:23:9:1 | functio ... ic1);\\n} |
| src/express.js:5:16:5:18 | req | src/express.js:4:23:9:1 | functio ... res);\\n} |
| src/express.js:6:26:6:28 | req | src/express.js:4:23:9:1 | functio ... res);\\n} |
| src/express.js:23:3:23:5 | req | src/express.js:22:30:32:1 | functio ... ar');\\n} |
@@ -1027,6 +1096,8 @@ test_RequestExpr
| src/express.js:49:3:49:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} |
| src/express.js:50:3:50:5 | req | src/express.js:46:22:51:1 | functio ... ame];\\n} |
| src/inheritedFromNode.js:7:2:7:4 | req | src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} |
| src/params.js:5:17:5:19 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/params.js:6:17:6:19 | req | src/params.js:4:18:12:1 | (req, r ... }\\n} |
| src/passport.js:28:2:28:4 | req | src/passport.js:27:4:29:1 | functio ... ccss`\\n} |
| src/responseExprs.js:17:5:17:7 | req | src/responseExprs.js:16:30:42:1 | functio ... }\\n} |
test_RequestExprStandalone
@@ -1044,7 +1115,9 @@ test_RouteHandler_getARequestExpr
| src/express2.js:4:32:4:76 | functio ... esult } | src/express2.js:4:60:4:66 | request |
| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:14:5:16 | req |
| src/express3.js:4:23:7:1 | functio ... al");\\n} | src/express3.js:5:35:5:37 | req |
| src/express4.js:4:23:6:1 | functio ... uery;\\n} | src/express4.js:5:27:5:29 | req |
| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:5:27:5:29 | req |
| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:6:18:6:20 | req |
| src/express4.js:4:23:9:1 | functio ... ic1);\\n} | src/express4.js:7:18:7:20 | req |
| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:5:16:5:18 | req |
| src/express.js:4:23:9:1 | functio ... res);\\n} | src/express.js:6:26:6:28 | req |
| src/express.js:22:30:32:1 | functio ... ar');\\n} | src/express.js:23:3:23:5 | req |
@@ -1060,5 +1133,7 @@ test_RouteHandler_getARequestExpr
| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:49:3:49:5 | req |
| src/express.js:46:22:51:1 | functio ... ame];\\n} | src/express.js:50:3:50:5 | req |
| src/inheritedFromNode.js:4:15:8:1 | functio ... .url;\\n} | src/inheritedFromNode.js:7:2:7:4 | req |
| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:5:17:5:19 | req |
| src/params.js:4:18:12:1 | (req, r ... }\\n} | src/params.js:6:17:6:19 | req |
| src/passport.js:27:4:29:1 | functio ... ccss`\\n} | src/passport.js:28:2:28:4 | req |
| src/responseExprs.js:16:30:42:1 | functio ... }\\n} | src/responseExprs.js:17:5:17:7 | req |

View File

@@ -3,3 +3,4 @@
| IncompleteUrlSchemeCheck.js:23:9:23:43 | badProt ... scheme) | This check does not consider vbscript:. |
| IncompleteUrlSchemeCheck.js:30:9:30:43 | badProt ... scheme) | This check does not consider vbscript:. |
| IncompleteUrlSchemeCheck.js:37:9:37:31 | scheme ... script" | This check does not consider data: and vbscript:. |
| IncompleteUrlSchemeCheck.js:51:9:51:31 | scheme ... script" | This check does not consider data: and vbscript:. |

View File

@@ -45,3 +45,10 @@ function test6(url) {
return "about:blank";
return url;
}
function test7(url) {
let scheme = url.split(/:/)[0];
if (scheme === "javascript") // NOT OK
return "about:blank";
return url;
}

View File

@@ -4,6 +4,11 @@ const extract = tar.extract();
extract.on('entry', (header, stream, next) => {
const out = fs.createWriteStream(header.name);
if (header.linkname) {
fs.linkSync(header.linkname, "foo");
}
stream.pipe(out);
stream.on('end', () => {
next();

View File

@@ -5,6 +5,9 @@ nodes
| TarSlipBad.js:6:36:6:46 | header.name |
| TarSlipBad.js:6:36:6:46 | header.name |
| TarSlipBad.js:6:36:6:46 | header.name |
| TarSlipBad.js:9:17:9:31 | header.linkname |
| TarSlipBad.js:9:17:9:31 | header.linkname |
| TarSlipBad.js:9:17:9:31 | header.linkname |
| ZipSlipBad2.js:5:9:5:46 | fileName |
| ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path |
| ZipSlipBad2.js:5:37:5:46 | entry.path |
@@ -21,6 +24,11 @@ nodes
| ZipSlipBad.js:15:22:15:31 | entry.path |
| ZipSlipBad.js:16:30:16:37 | fileName |
| ZipSlipBad.js:16:30:16:37 | fileName |
| ZipSlipBad.js:22:11:22:31 | fileName |
| ZipSlipBad.js:22:22:22:31 | entry.path |
| ZipSlipBad.js:22:22:22:31 | entry.path |
| ZipSlipBad.js:23:28:23:35 | fileName |
| ZipSlipBad.js:23:28:23:35 | fileName |
| ZipSlipBadUnzipper.js:7:9:7:29 | fileName |
| ZipSlipBadUnzipper.js:7:20:7:29 | entry.path |
| ZipSlipBadUnzipper.js:7:20:7:29 | entry.path |
@@ -29,6 +37,7 @@ nodes
edges
| AdmZipBad.js:6:24:6:41 | zipEntry.entryName | AdmZipBad.js:6:24:6:41 | zipEntry.entryName |
| TarSlipBad.js:6:36:6:46 | header.name | TarSlipBad.js:6:36:6:46 | header.name |
| TarSlipBad.js:9:17:9:31 | header.linkname | TarSlipBad.js:9:17:9:31 | header.linkname |
| ZipSlipBad2.js:5:9:5:46 | fileName | ZipSlipBad2.js:6:22:6:29 | fileName |
| ZipSlipBad2.js:5:9:5:46 | fileName | ZipSlipBad2.js:6:22:6:29 | fileName |
| ZipSlipBad2.js:5:20:5:46 | 'output ... ry.path | ZipSlipBad2.js:5:9:5:46 | fileName |
@@ -42,6 +51,10 @@ edges
| ZipSlipBad.js:15:11:15:31 | fileName | ZipSlipBad.js:16:30:16:37 | fileName |
| ZipSlipBad.js:15:22:15:31 | entry.path | ZipSlipBad.js:15:11:15:31 | fileName |
| ZipSlipBad.js:15:22:15:31 | entry.path | ZipSlipBad.js:15:11:15:31 | fileName |
| ZipSlipBad.js:22:11:22:31 | fileName | ZipSlipBad.js:23:28:23:35 | fileName |
| ZipSlipBad.js:22:11:22:31 | fileName | ZipSlipBad.js:23:28:23:35 | fileName |
| ZipSlipBad.js:22:22:22:31 | entry.path | ZipSlipBad.js:22:11:22:31 | fileName |
| ZipSlipBad.js:22:22:22:31 | entry.path | ZipSlipBad.js:22:11:22:31 | fileName |
| ZipSlipBadUnzipper.js:7:9:7:29 | fileName | ZipSlipBadUnzipper.js:8:37:8:44 | fileName |
| ZipSlipBadUnzipper.js:7:9:7:29 | fileName | ZipSlipBadUnzipper.js:8:37:8:44 | fileName |
| ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | ZipSlipBadUnzipper.js:7:9:7:29 | fileName |
@@ -49,7 +62,9 @@ edges
#select
| AdmZipBad.js:6:24:6:41 | zipEntry.entryName | AdmZipBad.js:6:24:6:41 | zipEntry.entryName | AdmZipBad.js:6:24:6:41 | zipEntry.entryName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | AdmZipBad.js:6:24:6:41 | zipEntry.entryName | item path |
| TarSlipBad.js:6:36:6:46 | header.name | TarSlipBad.js:6:36:6:46 | header.name | TarSlipBad.js:6:36:6:46 | header.name | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | TarSlipBad.js:6:36:6:46 | header.name | item path |
| TarSlipBad.js:9:17:9:31 | header.linkname | TarSlipBad.js:9:17:9:31 | header.linkname | TarSlipBad.js:9:17:9:31 | header.linkname | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | TarSlipBad.js:9:17:9:31 | header.linkname | item path |
| ZipSlipBad2.js:6:22:6:29 | fileName | ZipSlipBad2.js:5:37:5:46 | entry.path | ZipSlipBad2.js:6:22:6:29 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad2.js:5:37:5:46 | entry.path | item path |
| ZipSlipBad.js:8:37:8:44 | fileName | ZipSlipBad.js:7:22:7:31 | entry.path | ZipSlipBad.js:8:37:8:44 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad.js:7:22:7:31 | entry.path | item path |
| ZipSlipBad.js:16:30:16:37 | fileName | ZipSlipBad.js:15:22:15:31 | entry.path | ZipSlipBad.js:16:30:16:37 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad.js:15:22:15:31 | entry.path | item path |
| ZipSlipBad.js:23:28:23:35 | fileName | ZipSlipBad.js:22:22:22:31 | entry.path | ZipSlipBad.js:23:28:23:35 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBad.js:22:22:22:31 | entry.path | item path |
| ZipSlipBadUnzipper.js:8:37:8:44 | fileName | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | ZipSlipBadUnzipper.js:8:37:8:44 | fileName | Unsanitized zip archive $@, which may contain '..', is used in a file system operation. | ZipSlipBadUnzipper.js:7:20:7:29 | entry.path | item path |

View File

@@ -15,3 +15,10 @@ fs.createReadStream('archive.zip')
const fileName = entry.path;
entry.pipe(Writer({path: fileName}));
});
fs.createReadStream('archive.zip')
.pipe(unzip.Parse())
.on('entry', entry => {
const fileName = entry.path;
var file = fs.openSync(fileName, "w");
});

View File

@@ -1,5 +1,6 @@
const fs = require('fs');
const unzip = require('unzip');
const path = require('path');
fs.createReadStream('archive.zip')
.pipe(unzip.Parse())
@@ -11,4 +12,6 @@ fs.createReadStream('archive.zip')
else {
console.log('skipping bad path', fileName);
}
fs.createWriteStream(path.join(cwd, path.join('/', fileName)));
});

View File

@@ -9,3 +9,18 @@ var fs = {};
* @return {void}
*/
fs.writeFileSync = function(filename, data) {};
/**
* @param {(string|Buffer)} srcpath
* @param {(string|Buffer)} dstpath
* @return {void}
*/
fs.linkSync = function(srcpath, dstpath) {};
/**
* @param {(string|Buffer)} path
* @param {(string|number)} flags
* @param {number=} mode
* @return {number}
*/
fs.openSync = function(path, flags, mode) {};

View File

@@ -357,6 +357,12 @@ nodes
| tst.js:366:21:366:26 | target |
| tst.js:369:18:369:23 | target |
| tst.js:369:18:369:23 | target |
| tst.js:377:7:377:39 | target |
| tst.js:377:16:377:32 | document.location |
| tst.js:377:16:377:32 | document.location |
| tst.js:377:16:377:39 | documen ... .search |
| tst.js:380:18:380:23 | target |
| tst.js:380:18:380:23 | target |
| typeahead.js:20:13:20:45 | target |
| typeahead.js:20:22:20:38 | document.location |
| typeahead.js:20:22:20:38 | document.location |
@@ -689,6 +695,11 @@ edges
| tst.js:361:19:361:35 | document.location | tst.js:361:19:361:42 | documen ... .search |
| tst.js:361:19:361:35 | document.location | tst.js:361:19:361:42 | documen ... .search |
| tst.js:361:19:361:42 | documen ... .search | tst.js:361:10:361:42 | target |
| tst.js:377:7:377:39 | target | tst.js:380:18:380:23 | target |
| tst.js:377:7:377:39 | target | tst.js:380:18:380:23 | target |
| tst.js:377:16:377:32 | document.location | tst.js:377:16:377:39 | documen ... .search |
| tst.js:377:16:377:32 | document.location | tst.js:377:16:377:39 | documen ... .search |
| tst.js:377:16:377:39 | documen ... .search | tst.js:377:7:377:39 | target |
| typeahead.js:20:13:20:45 | target | typeahead.js:21:12:21:17 | target |
| typeahead.js:20:22:20:38 | document.location | typeahead.js:20:22:20:45 | documen ... .search |
| typeahead.js:20:22:20:38 | document.location | typeahead.js:20:22:20:45 | documen ... .search |
@@ -794,6 +805,7 @@ edges
| tst.js:362:16:362:21 | target | tst.js:361:19:361:35 | document.location | tst.js:362:16:362:21 | target | Cross-site scripting vulnerability due to $@. | tst.js:361:19:361:35 | document.location | user-provided value |
| tst.js:366:21:366:26 | target | tst.js:361:19:361:35 | document.location | tst.js:366:21:366:26 | target | Cross-site scripting vulnerability due to $@. | tst.js:361:19:361:35 | document.location | user-provided value |
| tst.js:369:18:369:23 | target | tst.js:361:19:361:35 | document.location | tst.js:369:18:369:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:361:19:361:35 | document.location | user-provided value |
| tst.js:380:18:380:23 | target | tst.js:377:16:377:32 | document.location | tst.js:380:18:380:23 | target | Cross-site scripting vulnerability due to $@. | tst.js:377:16:377:32 | document.location | user-provided value |
| typeahead.js:25:18:25:20 | val | typeahead.js:20:22:20:38 | document.location | typeahead.js:25:18:25:20 | val | Cross-site scripting vulnerability due to $@. | typeahead.js:20:22:20:38 | document.location | 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 |
| winjs.js:3:43:3:49 | tainted | winjs.js:2:17:2:33 | document.location | winjs.js:3:43:3:49 | tainted | Cross-site scripting vulnerability due to $@. | winjs.js:2:17:2:33 | document.location | user-provided value |

View File

@@ -357,6 +357,12 @@ nodes
| tst.js:366:21:366:26 | target |
| tst.js:369:18:369:23 | target |
| tst.js:369:18:369:23 | target |
| tst.js:377:7:377:39 | target |
| tst.js:377:16:377:32 | document.location |
| tst.js:377:16:377:32 | document.location |
| tst.js:377:16:377:39 | documen ... .search |
| tst.js:380:18:380:23 | target |
| tst.js:380:18:380:23 | target |
| typeahead.js:9:28:9:30 | loc |
| typeahead.js:9:28:9:30 | loc |
| typeahead.js:10:16:10:18 | loc |
@@ -693,6 +699,11 @@ edges
| tst.js:361:19:361:35 | document.location | tst.js:361:19:361:42 | documen ... .search |
| tst.js:361:19:361:35 | document.location | tst.js:361:19:361:42 | documen ... .search |
| tst.js:361:19:361:42 | documen ... .search | tst.js:361:10:361:42 | target |
| tst.js:377:7:377:39 | target | tst.js:380:18:380:23 | target |
| tst.js:377:7:377:39 | target | tst.js:380:18:380:23 | target |
| tst.js:377:16:377:32 | document.location | tst.js:377:16:377:39 | documen ... .search |
| tst.js:377:16:377:32 | document.location | tst.js:377:16:377:39 | documen ... .search |
| tst.js:377:16:377:39 | documen ... .search | tst.js:377:7:377:39 | target |
| 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

@@ -372,3 +372,13 @@ function thisNodes() {
$.fn[pluginName] = myPlugin;
}
function test() {
var target = document.location.search
// NOT OK
$('myId').html(target)
// OK
$('myid').html(document.location.href.split("?")[0]);
}

View File

@@ -0,0 +1,8 @@
| UnsafeHtmlExpansion.js:6:2:9:2 | html.re ... nded\\n\\t) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:7:3:7:95 | /<(?!ar ... )\\/>/gi | this regular expression |
| UnsafeHtmlExpansion.js:10:2:10:68 | html.re ... panded) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:10:15:10:57 | /<(([a- ... )\\/>/gi | this regular expression |
| UnsafeHtmlExpansion.js:13:2:16:2 | html.re ... nded\\n\\t) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:14:3:14:75 | /<(?!ar ... )\\/>/gi | this regular expression |
| UnsafeHtmlExpansion.js:17:2:17:48 | html.re ... panded) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:17:15:17:37 | /<(([\\w ... )\\/>/gi | this regular expression |
| UnsafeHtmlExpansion.js:20:2:23:2 | html.re ... nded\\n\\t) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:21:3:21:76 | /<(?!ar ... )\\/>/gi | this regular expression |
| UnsafeHtmlExpansion.js:24:2:24:49 | html.re ... panded) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:24:15:24:38 | /<(([\\w ... )\\/>/gi | this regular expression |
| UnsafeHtmlExpansion.js:26:2:26:39 | html.re ... panded) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:2:23:2:45 | /<(([\\w ... )\\/>/gi | this regular expression |
| UnsafeHtmlExpansion.js:30:2:30:37 | html.re ... panded) | This self-closing HTML tag expansion invalidates prior sanitization as $@ may match part of an attribute value. | UnsafeHtmlExpansion.js:2:23:2:45 | /<(([\\w ... )\\/>/gi | this regular expression |

View File

@@ -0,0 +1,39 @@
(function(){
let defaultPattern = /<(([\w:]+)[^>]*)\/>/gi;
let expanded = "<$1></$2>";
// lib1
html.replace(
/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,
expanded
); // NOT OK
html.replace(/<(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, expanded); // NOT OK
// lib2
html.replace(
/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
expanded
); // NOT OK
html.replace(/<(([\w:]+)[^>]*)\/>/gi, expanded); // NOT OK
// lib3
html.replace(
/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,
expanded
); // NOT OK
html.replace(/<(([\w:-]+)[^>]*)\/>/gi, expanded); // NOT OK
html.replace(defaultPattern, expanded); // NOT OK
function getPattern() {
return defaultPattern;
}
html.replace(getPattern(), expanded); // NOT OK
function getExpanded() {
return expanded;
}
html.replace(defaultPattern, getExpanded()); // NOT OK (but not tracking the expansion string)
html.replace(defaultPattern, something); // OK (possibly)
defaultPattern.match(something); // OK (possibly)
getPattern().match(something); // OK (possibly)
});

View File

@@ -0,0 +1 @@
Security/CWE-116/UnsafeHtmlExpansion.ql

View File

@@ -80,6 +80,37 @@ nodes
| PrototypePollutionUtility/path-assignment.js:61:12:61:18 | keys[i] |
| PrototypePollutionUtility/path-assignment.js:61:12:61:18 | keys[i] |
| PrototypePollutionUtility/path-assignment.js:61:12:61:18 | keys[i] |
| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key |
| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key |
| PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] |
| PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] |
| PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] |
| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target |
| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target |
| PrototypePollutionUtility/path-assignment.js:69:18:69:23 | target |
| PrototypePollutionUtility/path-assignment.js:69:18:69:23 | target |
| PrototypePollutionUtility/path-assignment.js:69:18:69:23 | target |
| PrototypePollutionUtility/path-assignment.js:69:18:69:48 | target[ ... ] \|\| {} |
| PrototypePollutionUtility/path-assignment.js:69:18:69:48 | target[ ... ] \|\| {} |
| PrototypePollutionUtility/path-assignment.js:69:25:69:27 | key |
| PrototypePollutionUtility/path-assignment.js:69:25:69:27 | key |
| PrototypePollutionUtility/path-assignment.js:69:25:69:27 | key |
| PrototypePollutionUtility/path-assignment.js:69:32:69:37 | target |
| PrototypePollutionUtility/path-assignment.js:69:32:69:37 | target |
| PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] |
| PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] |
| PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} |
| PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} |
| PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} |
| PrototypePollutionUtility/path-assignment.js:69:39:69:41 | key |
| PrototypePollutionUtility/path-assignment.js:69:39:69:41 | key |
| PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target |
| PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target |
| PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target |
| PrototypePollutionUtility/path-assignment.js:71:12:71:18 | keys[i] |
| PrototypePollutionUtility/path-assignment.js:71:12:71:18 | keys[i] |
| PrototypePollutionUtility/path-assignment.js:71:12:71:18 | keys[i] |
| PrototypePollutionUtility/path-assignment.js:71:12:71:18 | keys[i] |
| PrototypePollutionUtility/tests.js:3:25:3:27 | dst |
| PrototypePollutionUtility/tests.js:3:25:3:27 | dst |
| PrototypePollutionUtility/tests.js:3:30:3:32 | src |
@@ -1378,6 +1409,39 @@ edges
| PrototypePollutionUtility/path-assignment.js:59:39:59:41 | key | PrototypePollutionUtility/path-assignment.js:59:32:59:42 | target[key] |
| PrototypePollutionUtility/path-assignment.js:59:39:59:41 | key | PrototypePollutionUtility/path-assignment.js:59:32:59:42 | target[key] |
| PrototypePollutionUtility/path-assignment.js:61:12:61:18 | keys[i] | PrototypePollutionUtility/path-assignment.js:61:12:61:18 | keys[i] |
| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | PrototypePollutionUtility/path-assignment.js:69:25:69:27 | key |
| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | PrototypePollutionUtility/path-assignment.js:69:25:69:27 | key |
| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | PrototypePollutionUtility/path-assignment.js:69:25:69:27 | key |
| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | PrototypePollutionUtility/path-assignment.js:69:25:69:27 | key |
| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | PrototypePollutionUtility/path-assignment.js:69:39:69:41 | key |
| PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key | PrototypePollutionUtility/path-assignment.js:69:39:69:41 | key |
| PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key |
| PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key |
| PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key |
| PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:68:13:68:25 | key |
| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:69:18:69:23 | target |
| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:69:18:69:23 | target |
| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:69:18:69:23 | target |
| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:69:18:69:23 | target |
| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:69:32:69:37 | target |
| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:69:32:69:37 | target |
| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target |
| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target |
| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target |
| PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target | PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target |
| PrototypePollutionUtility/path-assignment.js:69:18:69:48 | target[ ... ] \|\| {} | PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target |
| PrototypePollutionUtility/path-assignment.js:69:18:69:48 | target[ ... ] \|\| {} | PrototypePollutionUtility/path-assignment.js:69:9:69:48 | target |
| PrototypePollutionUtility/path-assignment.js:69:32:69:37 | target | PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] |
| PrototypePollutionUtility/path-assignment.js:69:32:69:37 | target | PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] |
| PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] | PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} |
| PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] | PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} |
| PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] | PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} |
| PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] | PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} |
| PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} | PrototypePollutionUtility/path-assignment.js:69:18:69:48 | target[ ... ] \|\| {} |
| PrototypePollutionUtility/path-assignment.js:69:32:69:48 | target[key] \|\| {} | PrototypePollutionUtility/path-assignment.js:69:18:69:48 | target[ ... ] \|\| {} |
| PrototypePollutionUtility/path-assignment.js:69:39:69:41 | key | PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] |
| PrototypePollutionUtility/path-assignment.js:69:39:69:41 | key | PrototypePollutionUtility/path-assignment.js:69:32:69:42 | target[key] |
| PrototypePollutionUtility/path-assignment.js:71:12:71:18 | keys[i] | PrototypePollutionUtility/path-assignment.js:71:12:71:18 | keys[i] |
| PrototypePollutionUtility/tests.js:3:25:3:27 | dst | PrototypePollutionUtility/tests.js:6:28:6:30 | dst |
| PrototypePollutionUtility/tests.js:3:25:3:27 | dst | PrototypePollutionUtility/tests.js:6:28:6:30 | dst |
| PrototypePollutionUtility/tests.js:3:25:3:27 | dst | PrototypePollutionUtility/tests.js:8:13:8:15 | dst |
@@ -2922,6 +2986,7 @@ edges
| PrototypePollutionUtility/path-assignment.js:15:13:15:18 | target | PrototypePollutionUtility/path-assignment.js:8:19:8:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:15:13:15:18 | target | The property chain $@ is recursively assigned to $@ without guarding against prototype pollution. | PrototypePollutionUtility/path-assignment.js:8:19:8:25 | keys[i] | here | PrototypePollutionUtility/path-assignment.js:15:13:15:18 | target | target |
| PrototypePollutionUtility/path-assignment.js:44:5:44:10 | target | PrototypePollutionUtility/path-assignment.js:41:19:41:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:44:5:44:10 | target | The property chain $@ is recursively assigned to $@ without guarding against prototype pollution. | PrototypePollutionUtility/path-assignment.js:41:19:41:25 | keys[i] | here | PrototypePollutionUtility/path-assignment.js:44:5:44:10 | target | target |
| PrototypePollutionUtility/path-assignment.js:61:5:61:10 | target | PrototypePollutionUtility/path-assignment.js:58:19:58:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:61:5:61:10 | target | The property chain $@ is recursively assigned to $@ without guarding against prototype pollution. | PrototypePollutionUtility/path-assignment.js:58:19:58:25 | keys[i] | here | PrototypePollutionUtility/path-assignment.js:61:5:61:10 | target | target |
| PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target | PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target | The property chain $@ is recursively assigned to $@ without guarding against prototype pollution. | PrototypePollutionUtility/path-assignment.js:68:19:68:25 | keys[i] | here | PrototypePollutionUtility/path-assignment.js:71:5:71:10 | target | target |
| PrototypePollutionUtility/tests.js:8:13:8:15 | dst | PrototypePollutionUtility/tests.js:4:14:4:16 | key | PrototypePollutionUtility/tests.js:8:13:8:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | PrototypePollutionUtility/tests.js:4:21:4:23 | src | src | PrototypePollutionUtility/tests.js:8:13:8:15 | dst | dst |
| PrototypePollutionUtility/tests.js:18:13:18:15 | dst | PrototypePollutionUtility/tests.js:14:30:14:32 | key | PrototypePollutionUtility/tests.js:18:13:18:15 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | PrototypePollutionUtility/tests.js:14:17:14:19 | src | src | PrototypePollutionUtility/tests.js:18:13:18:15 | dst | dst |
| PrototypePollutionUtility/tests.js:36:9:36:11 | dst | PrototypePollutionUtility/tests.js:25:18:25:20 | key | PrototypePollutionUtility/tests.js:36:9:36:11 | dst | Properties are copied from $@ to $@ without guarding against prototype pollution. | PrototypePollutionUtility/tests.js:25:25:25:30 | source | source | PrototypePollutionUtility/tests.js:36:9:36:11 | dst | dst |

View File

@@ -60,3 +60,13 @@ function assignToPathWithHelper(target, path, value, sep) {
}
target[keys[i]] = value; // NOT OK
}
function spltOnRegexp(target, path, value) {
let keys = path.split(/\./);
let i;
for (i = 0; i < keys.length - 1; ++i) {
let key = keys[i];
target = target[key] = target[key] || {};
}
target[keys[i]] = value; // NOT OK
}

View File

@@ -55,6 +55,18 @@ nodes
| tst10.js:14:33:14:49 | document.location |
| tst10.js:14:33:14:49 | document.location |
| tst10.js:14:33:14:56 | documen ... .search |
| tst12.js:3:9:3:50 | urlParts |
| tst12.js:3:20:3:34 | window.location |
| tst12.js:3:20:3:34 | window.location |
| tst12.js:3:20:3:34 | window.location |
| tst12.js:3:20:3:39 | window.location.hash |
| tst12.js:3:20:3:50 | window. ... it('?') |
| tst12.js:4:9:4:45 | loc |
| tst12.js:4:15:4:22 | urlParts |
| tst12.js:4:15:4:25 | urlParts[0] |
| tst12.js:4:15:4:45 | urlPart ... s.value |
| tst12.js:5:23:5:25 | loc |
| tst12.js:5:23:5:25 | loc |
| tst.js:2:19:2:69 | /.*redi ... n.href) |
| tst.js:2:19:2:72 | /.*redi ... ref)[1] |
| tst.js:2:19:2:72 | /.*redi ... ref)[1] |
@@ -120,6 +132,18 @@ edges
| tst10.js:14:33:14:49 | document.location | tst10.js:14:33:14:56 | documen ... .search |
| tst10.js:14:33:14:56 | documen ... .search | tst10.js:14:17:14:56 | 'https: ... .search |
| tst10.js:14:33:14:56 | documen ... .search | tst10.js:14:17:14:56 | 'https: ... .search |
| tst12.js:3:9:3:50 | urlParts | tst12.js:4:15:4:22 | urlParts |
| tst12.js:3:20:3:34 | window.location | tst12.js:3:20:3:39 | window.location.hash |
| tst12.js:3:20:3:34 | window.location | tst12.js:3:20:3:39 | window.location.hash |
| tst12.js:3:20:3:34 | window.location | tst12.js:3:20:3:39 | window.location.hash |
| tst12.js:3:20:3:39 | window.location.hash | tst12.js:3:20:3:50 | window. ... it('?') |
| tst12.js:3:20:3:50 | window. ... it('?') | tst12.js:3:9:3:50 | urlParts |
| tst12.js:4:9:4:45 | loc | tst12.js:5:23:5:25 | loc |
| tst12.js:4:9:4:45 | loc | tst12.js:5:23:5:25 | loc |
| tst12.js:4:15:4:22 | urlParts | tst12.js:4:15:4:25 | urlParts[0] |
| tst12.js:4:15:4:25 | urlParts[0] | tst12.js:4:15:4:45 | urlPart ... s.value |
| tst12.js:4:15:4:45 | urlPart ... s.value | tst12.js:4:9:4:45 | loc |
| tst12.js:5:23:5:25 | loc | tst12.js:3:20:3:34 | window.location |
| tst.js:2:19:2:69 | /.*redi ... n.href) | tst.js:2:19:2:72 | /.*redi ... ref)[1] |
| tst.js:2:19:2:69 | /.*redi ... n.href) | tst.js:2:19:2:72 | /.*redi ... ref)[1] |
| tst.js:2:47:2:63 | document.location | tst.js:2:47:2:68 | documen ... on.href |
@@ -142,5 +166,6 @@ edges
| tst10.js:8:17:8:47 | '//' + ... .search | tst10.js:8:24:8:40 | document.location | tst10.js:8:17:8:47 | '//' + ... .search | Untrusted URL redirection due to $@. | tst10.js:8:24:8:40 | document.location | user-provided value |
| tst10.js:11:17:11:50 | '//foo' ... .search | tst10.js:11:27:11:43 | document.location | tst10.js:11:17:11:50 | '//foo' ... .search | Untrusted URL redirection due to $@. | tst10.js:11:27:11:43 | document.location | user-provided value |
| tst10.js:14:17:14:56 | 'https: ... .search | tst10.js:14:33:14:49 | document.location | tst10.js:14:17:14:56 | 'https: ... .search | Untrusted URL redirection due to $@. | tst10.js:14:33:14:49 | document.location | user-provided value |
| tst12.js:5:23:5:25 | loc | tst12.js:3:20:3:34 | window.location | tst12.js:5:23:5:25 | loc | Untrusted URL redirection due to $@. | tst12.js:3:20:3:34 | window.location | user-provided value |
| tst.js:2:19:2:72 | /.*redi ... ref)[1] | tst.js:2:47:2:63 | document.location | tst.js:2:19:2:72 | /.*redi ... ref)[1] | Untrusted URL redirection due to $@. | tst.js:2:47:2:63 | document.location | user-provided value |
| tst.js:6:20:6:59 | indirec ... ref)[1] | tst.js:6:34:6:50 | document.location | tst.js:6:20:6:59 | indirec ... ref)[1] | Untrusted URL redirection due to $@. | tst.js:6:34:6:50 | document.location | user-provided value |

View File

@@ -0,0 +1,9 @@
// OK
function foo() {
var urlParts = document.location.href.split('?');
var loc = urlParts[0] + "?" + boxes.value;
window.location = loc
// Also OK.
window.location.replace(window.location.href.split("#")[0] + "#mappage");
}

View File

@@ -0,0 +1,6 @@
// NOT OK
function foo() {
var urlParts = window.location.hash.split('?');
var loc = urlParts[0] + "?" + boxes.value;
window.location = loc
}