Merge branch 'js-team-sprint' into js/insecure-http-options

This commit is contained in:
Esben Sparre Andreasen
2020-06-22 11:25:25 +02:00
committed by GitHub
56 changed files with 1645 additions and 56 deletions

View File

@@ -45,6 +45,7 @@
+ semmlecode-javascript-queries/Security/CWE-730/RegExpInjection.ql: /Security/CWE/CWE-730
+ semmlecode-javascript-queries/Security/CWE-754/UnvalidatedDynamicMethodCall.ql: /Security/CWE/CWE-754
+ semmlecode-javascript-queries/Security/CWE-770/MissingRateLimiting.ql: /Security/CWE/CWE-770
+ semmlecode-javascript-queries/Security/CWE-770/ResourceExhaustion.ql: /Security/CWE/CWE-770
+ semmlecode-javascript-queries/Security/CWE-776/XmlBomb.ql: /Security/CWE/CWE-776
+ semmlecode-javascript-queries/Security/CWE-798/HardcodedCredentials.ql: /Security/CWE/CWE-798
+ semmlecode-javascript-queries/Security/CWE-807/ConditionalBypass.ql: /Security/CWE/CWE-807

View File

@@ -5,20 +5,33 @@
<overview>
<p>
Placeholder
Libraries like <code>express</code> provide easy methods for serving entire
directories of static files from a web server.
However, using these can sometimes lead to accidental information exposure.
If for example the <code>node_modules</code> folder is served, then an attacker
can access the <code>_where</code> field from a <code>package.json</code> file,
which gives access to the absolute path of the file.
</p>
</overview>
<recommendation>
<p>
Placeholder
Limit which folders of static files are served from a web server.
</p>
</recommendation>
<example>
<p>
Placeholder
In the example below, all the files from the <code>node_modules</code> are served.
This allows clients to easily access all the files inside that folder,
which includes potentially private information inside <code>package.json</code> files.
</p>
<sample src="examples/PrivateFileExposure.js"/>
<p>
The issue has been fixed below by only serving specific folders within the
<code>node_modules</code> folder.
</p>
<sample src="examples/PrivateFileExposureFixed.js"/>
</example>
<references>

View File

@@ -69,19 +69,33 @@ pragma[noinline]
Folder getAPackageJSONFolder() { result = any(PackageJSON json).getFile().getParentContainer() }
/**
* Gets a reference to `dirname` that might cause information to be leaked.
* That can happen if there is a `package.json` file in the same folder.
* (It is assumed that the presence of a `package.json` file means that a `node_modules` folder can also exist.
* Gets a reference to `dirname`, the home folder, the current working folder, or the root folder.
* All of these might cause information to be leaked.
*
* For `dirname` that can happen if there is a `package.json` file in the same folder.
* It is assumed that the presence of a `package.json` file means that a `node_modules` folder can also exist.
*
* For the root/home/working folder, they contain so much information that they must leak information somehow (e.g. ssh keys in the `~/.ssh` folder).
*/
DataFlow::Node dirname() {
DataFlow::Node getALeakingFolder(string description) {
exists(ModuleScope ms | result.asExpr() = ms.getVariable("__dirname").getAnAccess()) and
result.getFile().getParentContainer() = getAPackageJSONFolder()
result.getFile().getParentContainer() = getAPackageJSONFolder() and
description = "the folder " + result.getFile().getParentContainer().getRelativePath()
or
result.getAPredecessor() = dirname()
result = DataFlow::moduleImport("os").getAMemberCall("homedir") and
description = "the home folder "
or
result.mayHaveStringValue("/") and
description = "the root folder"
or
result.getStringValue() = [".", "./"] and
description = "the current working folder"
or
result.getAPredecessor() = getALeakingFolder(description)
or
exists(StringOps::ConcatenationRoot root | root = result |
root.getNumOperand() = 2 and
root.getOperand(0) = dirname() and
root.getOperand(0) = getALeakingFolder(description) and
root.getOperand(1).getStringValue() = "/"
)
}
@@ -94,18 +108,17 @@ DataFlow::Node getAPrivateFolderPath(string description) {
result = getANodeModulePath(path) and description = "the folder \"" + path + "\""
)
or
result = dirname() and
description = "the folder " + result.getFile().getParentContainer().getRelativePath()
or
result.getStringValue() = [".", "./"] and
description = "the current working folder"
result = getALeakingFolder(description)
}
/**
* Gest a call that serves the folder `path` to the public.
*/
DataFlow::CallNode servesAPrivateFolder(string description) {
result = DataFlow::moduleMember("express", "static").getACall() and
result = DataFlow::moduleMember(["express", "connect"], "static").getACall() and
result.getArgument(0) = getAPrivateFolderPath(description)
or
result = DataFlow::moduleImport("serve-static").getACall() and
result.getArgument(0) = getAPrivateFolderPath(description)
}

View File

@@ -0,0 +1,6 @@
var express = require('express');
var app = express();
app.use('/node_modules', express.static(path.resolve(__dirname, '../node_modules')));

View File

@@ -0,0 +1,7 @@
var express = require('express');
var app = express();
app.use("jquery", express.static('./node_modules/jquery/dist'));
app.use("bootstrap", express.static('./node_modules/bootstrap/dist'));

View File

@@ -0,0 +1,36 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Sensitive information included in a build artifact can allow an attacker to access
the sensitive information if the artifact is published.
</p>
</overview>
<recommendation>
<p>
Only store information that is meant to be publicly available in a build artifact.
</p>
</recommendation>
<example>
<p>
The following example creates a <code>webpack</code> configuration that inserts all environment
variables from the host into the build artifact:
</p>
<sample src="examples/build-leak.js"/>
<p>
The environment variables might include API keys or other sensitive information, and the build-system
should instead insert only the environment variables that are supposed to be public.
</p>
<p>
The issue has been fixed below, where only the <code>DEBUG</code> environment variable is inserted into the artifact.
</p>
<sample src="examples/build-leak-fixed.js"/>
</example>
<references>
<li>webpack: <a href="https://webpack.js.org/plugins/define-plugin/">DefinePlugin API</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,23 @@
/**
* @name Storage of sensitive information in build artifact
* @description Including sensitive information in a build artifact can
* expose it to an attacker.
* @kind path-problem
* @problem.severity error
* @precision high
* @id js/build-artifact-leak
* @tags security
* external/cwe/cwe-312
* external/cwe/cwe-315
* external/cwe/cwe-359
*/
import javascript
import semmle.javascript.security.dataflow.BuildArtifactLeak::BuildArtifactLeak
import DataFlow::PathGraph
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink,
"Sensitive data returned by $@ is stored in a build artifact here.", source.getNode(),
source.getNode().(CleartextLogging::Source).describe()

View File

@@ -0,0 +1,9 @@
const webpack = require("webpack");
module.exports = [{
plugins: [
new webpack.DefinePlugin({
'process.env': JSON.stringify({ DEBUG: process.env.DEBUG })
})
]
}];

View File

@@ -0,0 +1,9 @@
const webpack = require("webpack");
module.exports = [{
plugins: [
new webpack.DefinePlugin({
"process.env": JSON.stringify(process.env)
})
]
}];

View File

@@ -4,33 +4,62 @@
<qhelp>
<overview>
<p>
Placeholder
Generating secure random numbers can be an important part of creating a
secure software system. This can be done using APIs that create
cryptographically secure random numbers.
</p>
<p>
However, using some mathematical operations on these cryptographically
secure random numbers can create biased results, where some outcomes
are more likely than others.
Such biased results can make it easier for an attacker to guess the random
numbers, and thereby break the security of the software system.
</p>
</overview>
<recommendation>
<p>
Placeholder.
Be very careful not to introduce bias when performing mathematical operations
on cryptographically secure random numbers.
</p>
<p>
If possible, avoid performing mathematical operations on cryptographically secure
random numbers at all, and use a preexisting library instead.
</p>
</recommendation>
<example>
<p>
Placeholder
The example below uses the modulo operator to create an array of 10 random digits
using random bytes as the source for randomness.
</p>
<sample src="examples/bad-random.js" />
<p>
The random byte is a uniformly random value between 0 and 255, and thus the result
from using the modulo operator is slightly more likely to be between 0 and 5 than
between 6 and 9.
</p>
<p>
The issue has been fixed in the code below by using a library that correctly generates
cryptographically secure random values.
</p>
<sample src="examples/bad-random-fixed.js" />
<p>
Alternatively, the issue can be fixed by fixing the math in the original code.
In the code below the random byte is discarded if the value is greater than or equal to 250.
Thus the modulo operator is used on a uniformly random number between 0 and 249, which
results in a uniformly random digit between 0 and 9.
</p>
<sample src="examples/bad-random-fixed2.js" />
</example>
<references>
<li>NIST, FIPS 140 Annex a: <a href="http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf"> Approved Security Functions</a>.</li>
<li>NIST, SP 800-131A: <a href="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf"> Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths</a>.</li>
<li>Stack Overflow: <a href="https://stackoverflow.com/questions/3956478/understanding-randomness">Understanding “randomness”</a>.</li>
<li>OWASP: <a href="https://owasp.org/www-community/vulnerabilities/Insecure_Randomness">Insecure Randomness</a>.</li>
<li>OWASP: <a
href="https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#rule---use-strong-approved-authenticated-encryption">Rule
- Use strong approved cryptographic algorithms</a>.
</li>
<li>Stack Overflow: <a href="https://stackoverflow.com/questions/3956478/understanding-randomness">Understanding “randomness”</a>.</li>
</references>
</qhelp>

View File

@@ -1,5 +1,5 @@
/**
* @name Creating biased random numbers from cryptographically secure source.
* @name Creating biased random numbers from a cryptographically secure source.
* @description Some mathematical operations on random numbers can cause bias in
* the results and compromise security.
* @kind problem
@@ -132,6 +132,18 @@ DataFlow::Node goodRandom(DataFlow::SourceNode source) {
result = goodRandom(DataFlow::TypeTracker::end(), source)
}
/**
* Gets a node that is passed to a rounding function from `Math`, using type-backtracker `t`.
*/
DataFlow::Node isRounded(DataFlow::TypeBackTracker t) {
t.start() and
result = DataFlow::globalVarRef("Math").getAMemberCall(["round", "floor", "ceil"]).getArgument(0)
or
exists(DataFlow::TypeBackTracker t2 | t2 = t.smallstep(result, isRounded(t2)))
or
InsecureRandomness::isAdditionalTaintStep(result, isRounded(t.continue()))
}
/**
* Gets a node that that produces a biased result from otherwise cryptographically secure random numbers produced by `source`.
*/
@@ -153,10 +165,7 @@ DataFlow::Node badCrypto(string description, DataFlow::SourceNode source) {
goodRandom(source).asExpr() = div.getLeftOperand() and
description = "division and rounding the result" and
not div.getRightOperand() = isPowerOfTwoMinusOne().asExpr() and // division by (2^n)-1 most of the time produces a uniformly random number between 0 and 1.
DataFlow::globalVarRef("Math")
.getAMemberCall(["round", "floor", "ceil"])
.getArgument(0)
.asExpr() = div
div = isRounded(DataFlow::TypeBackTracker::end()).asExpr()
)
or
// modulo - only bad if not by a power of 2 - and the result is not checked for bias

View File

@@ -0,0 +1,3 @@
const cryptoRandomString = require('crypto-random-string');
const digits = cryptoRandomString({length: 10, type: 'numeric'});

View File

@@ -0,0 +1,10 @@
const crypto = require('crypto');
const digits = [];
while (digits.length < 10) {
const byte = crypto.randomBytes(1)[0];
if (byte >= 250) {
continue;
}
digits.push(byte % 10); // OK
}

View File

@@ -0,0 +1,6 @@
const crypto = require('crypto');
const digits = [];
for (let i = 0; i < 10; i++) {
digits.push(crypto.randomBytes(1)[0] % 10); // NOT OK
}

View File

@@ -0,0 +1,113 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Applications are constrained by how many resources they can make use
of. Failing to respect these constraints may cause the application to
be unresponsive or crash. It is therefore problematic if attackers
can control the sizes or lifetimes of allocated objects.
</p>
</overview>
<recommendation>
<p>
Ensure that attackers can not control object sizes and their
lifetimes. If object sizes and lifetimes must be controlled by
external parties, ensure you restrict the object sizes and lifetimes so that
they are within acceptable ranges.
</p>
</recommendation>
<example>
<p>
The following example allocates a buffer with a user-controlled
size.
</p>
<sample src="examples/ResourceExhaustion_buffer.js" />
<p>
This is problematic since an attacker can choose a size
that makes the application run out of memory. Even worse, in older
versions of Node.js, this could leak confidential memory.
To prevent such attacks, limit the buffer size:
</p>
<sample src="examples/ResourceExhaustion_buffer_fixed.js" />
</example>
<example>
<p>
As another example, consider an application that allocates an
array with a user-controlled size, and then fills it with values:
</p>
<sample src="examples/ResourceExhaustion_array.js" />
<p>
The allocation of the array itself is not problematic since arrays are
allocated sparsely, but the subsequent filling of the array will take
a long time, causing the application to be unresponsive, or even run
out of memory.
Again, a limit on the size will prevent the attack:
</p>
<sample src="examples/ResourceExhaustion_array_fixed.js" />
</example>
<example>
<p>
Finally, the following example lets a user choose a delay after
which a function is executed:
</p>
<sample src="examples/ResourceExhaustion_timeout.js" />
<p>
This is problematic because a large delay essentially makes the
application wait indefinitely before executing the function. Repeated
registrations of such delays will therefore use up all of the memory
in the application.
Again, a limit on the delay will prevent the attack:
</p>
<sample src="examples/ResourceExhaustion_timeout_fixed.js" />
</example>
<references>
</references>
</qhelp>

View File

@@ -0,0 +1,20 @@
/**
* @name Resource exhaustion
* @description Allocating objects or timers with user-controlled
* sizes or durations can cause resource exhaustion.
* @kind path-problem
* @problem.severity warning
* @id js/resource-exhaustion
* @precision high
* @tags security
* external/cwe/cwe-770
*/
import javascript
import DataFlow::PathGraph
import semmle.javascript.security.dataflow.ResourceExhaustion::ResourceExhaustion
from Configuration dataflow, DataFlow::PathNode source, DataFlow::PathNode sink
where dataflow.hasFlowPath(source, sink)
select sink, source, sink, sink.getNode().(Sink).getProblemDescription() + " from $@.", source,
"here"

View File

@@ -0,0 +1,10 @@
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
var size = parseInt(url.parse(req.url, true).query.size);
let dogs = new Array(size).fill(x => "dog"); // BAD
// ... use the dogs
});

View File

@@ -0,0 +1,16 @@
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
var size = parseInt(url.parse(req.url, true).query.size);
if (size > 1024) {
res.statusCode = 400;
res.end("Bad request.");
return;
}
let dogs = new Array(size).fill(x => "dog"); // GOOD
// ... use the dogs
});

View File

@@ -0,0 +1,10 @@
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
var size = parseInt(url.parse(req.url, true).query.size);
let buffer = Buffer.alloc(size); // BAD
// ... use the buffer
});

View File

@@ -0,0 +1,16 @@
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
var size = parseInt(url.parse(req.url, true).query.size);
if (size > 1024) {
res.statusCode = 400;
res.end("Bad request.");
return;
}
let buffer = Buffer.alloc(size); // GOOD
// ... use the buffer
});

View File

@@ -0,0 +1,9 @@
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
var delay = parseInt(url.parse(req.url, true).query.delay);
setTimeout(f, delay); // BAD
});

View File

@@ -0,0 +1,15 @@
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
var delay = parseInt(url.parse(req.url, true).query.delay);
if (delay > 1000) {
res.statusCode = 400;
res.end("Bad request.");
return;
}
setTimeout(f, delay); // GOOD
});

View File

@@ -0,0 +1,38 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Downloading executeables or other sensitive files over an unencrypted connection
can leave a server open to man-in-the-middle attacks (MITM).
Such an attack can allow an attacker to insert arbitrary content
into the downloaded file, and in the worst case, allow the attacker to execute
arbitrary code on the vulnerable system.
</p>
</overview>
<recommendation>
<p>
Use a secure transfer protocol when downloading executables or other sensitive files.
</p>
</recommendation>
<example>
<p>
In this example, a server downloads a shell script from a remote URL using the <code>node-fetch</code>
library, and then executes this shell script.
</p>
<sample src="examples/insecure-download.js" />
<p>
The HTTP protocol is vulnerable to MITM, and thus an attacker could potentially replace the downloaded
shell script with arbitrary code, which gives the attacker complete control over the system.
</p>
<p>
The issue has been fixed in the example below by replacing the HTTP protocol with the HTTPS protocol.
</p>
<sample src="examples/insecure-download.js" />
</example>
<references>
<li>OWASP: <a href="https://owasp.org/www-community/attacks/Man-in-the-middle_attack">Man-in-the-middle attack</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,20 @@
/**
* @name Download of sensitive file through insecure connection
* @description Downloading executables and other sensitive files over an insecure connection
* opens up for potential man-in-the-middle attacks.
* @kind path-problem
* @problem.severity error
* @precision high
* @id js/insecure-download
* @tags security
* external/cwe/cwe-829
*/
import javascript
import semmle.javascript.security.dataflow.InsecureDownload::InsecureDownload
import DataFlow::PathGraph
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "$@ of sensitive file from $@.",
sink.getNode().(Sink).getDownloadCall(), "Download", source.getNode(), "HTTP source"

View File

@@ -0,0 +1,6 @@
const fetch = require("node-fetch");
const cp = require("child_process");
fetch('http://mydownload.example.org/myscript.sh')
.then(res => res.text())
.then(script => cp.execSync(script));

View File

@@ -0,0 +1,6 @@
const fetch = require("node-fetch");
const cp = require("child_process");
fetch('https://mydownload.example.org/myscript.sh')
.then(res => res.text())
.then(script => cp.execSync(script));

View File

@@ -40,6 +40,11 @@ module ArrayTaintTracking {
succ = call
)
or
// `array.reduce` with tainted value in callback
call.(DataFlow::MethodCallNode).getMethodName() = "reduce" and
pred = call.getArgument(0).(DataFlow::FunctionNode).getAReturn() and // Require the argument to be a closure to avoid spurious call/return flow
succ = call
or
// `array.push(e)`, `array.unshift(e)`: if `e` is tainted, then so is `array`.
exists(string name |
name = "push" or

View File

@@ -620,4 +620,45 @@ module ClientRequest {
override DataFlow::Node getADataNode() { none() }
}
/**
* A call to `nugget` that downloads one of more files to a destination determined by an options object given as the second argument.
*/
class Nugget extends ClientRequest::Range, DataFlow::CallNode {
Nugget() { this = DataFlow::moduleImport("nugget").getACall() }
override DataFlow::Node getUrl() { result = getArgument(0) }
override DataFlow::Node getHost() { none() }
override DataFlow::Node getADataNode() { none() }
}
/**
* A shell execution of `curl` that downloads some file.
*/
class CurlDownload extends ClientRequest::Range {
SystemCommandExecution cmd;
CurlDownload() {
this = cmd and
(
cmd.getACommandArgument().getStringValue() = "curl" or
cmd
.getACommandArgument()
.(StringOps::ConcatenationRoot)
.getConstantStringParts()
.regexpMatch("curl .*")
)
}
override DataFlow::Node getUrl() {
result = cmd.getArgumentList().getALocalSource().getAPropertyWrite().getRhs() or
result = cmd.getACommandArgument().(StringOps::ConcatenationRoot).getALeaf()
}
override DataFlow::Node getHost() { none() }
override DataFlow::Node getADataNode() { none() }
}
}

View File

@@ -0,0 +1,45 @@
/**
* Provides a dataflow tracking configuration for reasoning about
* storage of sensitive information in build artifact.
*
* Note, for performance reasons: only import this file if
* `CleartextLogging::Configuration` is needed, otherwise
* `CleartextLoggingCustomizations` should be imported instead.
*/
import javascript
/**
* Classes and predicates for storage of sensitive information in build artifact query.
*/
module BuildArtifactLeak {
import BuildArtifactLeakCustomizations::BuildArtifactLeak
import CleartextLoggingCustomizations::CleartextLogging as CleartextLogging
/**
* A taint tracking configuration for storage of sensitive information in build artifact.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "BuildArtifactLeak" }
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel lbl) {
source.(CleartextLogging::Source).getLabel() = lbl
}
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel lbl) {
sink.(Sink).getLabel() = lbl
}
override predicate isSanitizer(DataFlow::Node node) {
node instanceof CleartextLogging::Barrier
}
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
CleartextLogging::isSanitizerEdge(pred, succ)
}
override predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node trg) {
CleartextLogging::isAdditionalTaintStep(src, trg)
}
}
}

View File

@@ -0,0 +1,32 @@
/**
* Provides default sinks for reasoning about storage of sensitive information
* in build artifact, as well as extension points for adding your own.
*/
import javascript
private import semmle.javascript.dataflow.InferredTypes
private import semmle.javascript.security.SensitiveActions::HeuristicNames
/**
* Sinks for storage of sensitive information in build artifact.
*/
module BuildArtifactLeak {
/**
* A data flow sink for storage of sensitive information in a build artifact.
*/
abstract class Sink extends DataFlow::Node {
/**
* Gets a data-flow label that leaks information for this sink.
*/
DataFlow::FlowLabel getLabel() { result.isTaint() }
}
/**
* An instantiation of `webpack.DefintePlugin` that stores information in a compiled JavaScript file.
*/
class WebpackDefinePluginSink extends Sink {
WebpackDefinePluginSink() {
this = DataFlow::moduleMember("webpack", "DefinePlugin").getAnInstantiation().getAnArgument()
}
}
}

View File

@@ -35,23 +35,11 @@ module CleartextLogging {
override predicate isSanitizer(DataFlow::Node node) { node instanceof Barrier }
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
succ.(DataFlow::PropRead).getBase() = pred
CleartextLogging::isSanitizerEdge(pred, succ)
}
override predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node trg) {
// A taint propagating data flow edge through objects: a tainted write taints the entire object.
exists(DataFlow::PropWrite write |
write.getRhs() = src and
trg.(DataFlow::SourceNode).flowsTo(write.getBase())
)
or
// Taint through the arguments object.
exists(DataFlow::CallNode call, Function f |
src = call.getAnArgument() and
f = call.getACallee() and
not call.isImprecise() and
trg.asExpr() = f.getArgumentsVariable().getAnAccess()
)
CleartextLogging::isAdditionalTaintStep(src, trg)
}
}
}

View File

@@ -176,17 +176,50 @@ module CleartextLogging {
override string describe() { result = "process environment" }
override DataFlow::FlowLabel getLabel() {
result.isTaint() or
result instanceof PartiallySensitiveMap
}
override DataFlow::FlowLabel getLabel() { result.isTaint() }
}
/**
* A flow label describing a map that might contain sensitive information in some properties.
* Property reads on such maps where the property name is fixed is unlikely to leak sensitive information.
* Holds if the edge `pred` -> `succ` should be sanitized for clear-text logging of sensitive information.
*/
class PartiallySensitiveMap extends DataFlow::FlowLabel {
PartiallySensitiveMap() { this = "PartiallySensitiveMap" }
predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
succ.(DataFlow::PropRead).getBase() = pred
}
/**
* Holds if the edge `src` -> `trg` is an additional taint-step for clear-text logging of sensitive information.
*/
predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node trg) {
// A taint propagating data flow edge through objects: a tainted write taints the entire object.
exists(DataFlow::PropWrite write |
write.getRhs() = src and
trg.(DataFlow::SourceNode).flowsTo(write.getBase())
)
or
// A property-copy step,
// dst[x] = src[x]
// dst[x] = JSON.stringify(src[x])
exists(DataFlow::PropWrite write, DataFlow::PropRead read |
read = write.getRhs()
or
exists(DataFlow::MethodCallNode stringify |
stringify = write.getRhs() and
stringify = DataFlow::globalVarRef("JSON").getAMethodCall("stringify") and
stringify.getArgument(0) = read
)
|
not exists(write.getPropertyName()) and
not exists(read.getPropertyName()) and
src = read.getBase() and
trg = write.getBase().getALocalSource()
)
or
// Taint through the arguments object.
exists(DataFlow::CallNode call, Function f |
src = call.getAnArgument() and
f = call.getACallee() and
not call.isImprecise() and
trg.asExpr() = f.getArgumentsVariable().getAnAccess()
)
}
}

View File

@@ -0,0 +1,27 @@
/**
* Provides a taint tracking configuration for reasoning about download of sensitive file through insecure connection.
*
* Note, for performance reasons: only import this file if
* `InsecureDownload::Configuration` is needed, otherwise
* `InsecureDownloadCustomizations` should be imported instead.
*/
import javascript
/**
* Classes and predicates for reasoning about download of sensitive file through insecure connection vulnerabilities.
*/
module InsecureDownload {
import InsecureDownloadCustomizations::InsecureDownload
/**
* A taint tracking configuration for download of sensitive file through insecure connection.
*/
class Configuration extends DataFlow::Configuration {
Configuration() { this = "InsecureDownload" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
}
}

View File

@@ -0,0 +1,70 @@
/**
* Provides default sources, sinks and sanitizers for reasoning about
* download of sensitive file through insecure connection, as well as
* extension points for adding your own.
*/
import javascript
/**
* Classes and predicates for reasoning about download of sensitive file through insecure connection vulnerabilities.
*/
module InsecureDownload {
/**
* A data flow source for download of sensitive file through insecure connection.
*/
abstract class Source extends DataFlow::Node { }
/**
* A data flow sink for download of sensitive file through insecure connection.
*/
abstract class Sink extends DataFlow::Node {
/**
* Gets the call that downloads the sensitive file.
*/
abstract DataFlow::Node getDownloadCall();
}
/**
* A sanitizer for download of sensitive file through insecure connection.
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* A HTTP or FTP URL that refers to a file with a sensitive file extension,
* seen as a source for download of sensitive file through insecure connection.
*/
class SensitiveFileUrl extends Source {
SensitiveFileUrl() {
exists(string str | str = this.getStringValue() |
str.regexpMatch("http://.*|ftp://.*") and
exists(string suffix | suffix = unsafeExtension() |
str.suffix(str.length() - suffix.length() - 1).toLowerCase() = "." + suffix
)
)
}
}
/**
* Gets a file-extension that can potentially be dangerous.
*
* Archives are included, because they often contain source-code.
*/
string unsafeExtension() {
result =
["exe", "dmg", "pkg", "tar.gz", "zip", "sh", "bat", "cmd", "app", "apk", "msi", "dmg",
"tar.gz", "zip", "js", "py", "jar", "war"]
}
/**
* A url downloaded by a client-request, seen as a sink for download of
* sensitive file through insecure connection.a
*/
class ClientRequestURL extends Sink {
ClientRequest request;
ClientRequestURL() { this = request.getUrl() }
override DataFlow::Node getDownloadCall() { result = request }
}
}

View File

@@ -0,0 +1,77 @@
/**
* Provides a taint tracking configuration for reasoning about
* resource exhaustion vulnerabilities (CWE-770).
*
* Note, for performance reasons: only import this file if
* `ResourceExhaustion::Configuration` is needed, otherwise
* `ResourceExhaustionCustomizations` should be imported instead.
*/
import javascript
import semmle.javascript.security.dataflow.LoopBoundInjectionCustomizations
module ResourceExhaustion {
import ResourceExhaustionCustomizations::ResourceExhaustion
/**
* A data flow configuration for resource exhaustion vulnerabilities.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "ResourceExhaustion" }
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
source.(Source).getAFlowLabel() = label
}
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
sink.(Sink).getAFlowLabel() = label
}
override predicate isAdditionalFlowStep(
DataFlow::Node src, DataFlow::Node dst, DataFlow::FlowLabel srclabel,
DataFlow::FlowLabel dstlabel
) {
dstlabel instanceof Label::Number and
isNumericFlowStep(src, dst)
or
// reuse most existing taint steps
super.isAdditionalFlowStep(src, dst) and
not dst.asExpr() instanceof AddExpr and
if dst.(DataFlow::MethodCallNode).calls(src, "toString")
then dstlabel.isTaint()
else srclabel = dstlabel
}
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
guard instanceof LoopBoundInjection::LengthCheckSanitizerGuard or
guard instanceof UpperBoundsCheckSanitizerGuard or
guard instanceof TypeTestGuard
}
}
/**
* Holds if data may flow from `src` to `dst` as a number.
*/
predicate isNumericFlowStep(DataFlow::Node src, DataFlow::Node dst) {
// steps that introduce or preserve a number
dst.(DataFlow::PropRead).accesses(src, ["length", "size"])
or
exists(DataFlow::CallNode c |
c = dst and
src = c.getAnArgument()
|
c = DataFlow::globalVarRef("Math").getAMemberCall(_) or
c = DataFlow::globalVarRef(["Number", "parseInt", "parseFloat"]).getACall()
)
or
exists(Expr dstExpr, Expr srcExpr |
dstExpr = dst.asExpr() and
srcExpr = src.asExpr()
|
dstExpr.(BinaryExpr).getAnOperand() = srcExpr and
not dstExpr instanceof AddExpr
or
dstExpr.(PlusExpr).getOperand() = srcExpr
)
}
}

View File

@@ -0,0 +1,187 @@
/**
* Provides default sources, sinks and sanitizers for reasoning about
* resource exhaustion vulnerabilities, as well as extension points for
* adding your own.
*/
import javascript
module ResourceExhaustion {
/**
* A data flow source for resource exhaustion vulnerabilities.
*/
abstract class Source extends DataFlow::Node {
/** Gets a flow label denoting the type of value for which this is a source. */
DataFlow::FlowLabel getAFlowLabel() { result.isTaint() }
}
/**
* A data flow sink for resource exhaustion vulnerabilities.
*/
abstract class Sink extends DataFlow::Node {
/** Gets a flow label denoting the type of value for which this is a sink. */
DataFlow::FlowLabel getAFlowLabel() { result instanceof Label::Number }
/**
* Gets a description of why this is a problematic sink.
*/
abstract string getProblemDescription();
}
/**
* A data flow sanitizer for resource exhaustion vulnerabilities.
*/
abstract class Sanitizer extends DataFlow::Node { }
/**
* Provides data flow labels for resource exhaustion vulnerabilities.
*/
module Label {
/**
* A number data flow label.
*/
class Number extends DataFlow::FlowLabel {
Number() { this = "number" }
}
}
/**
* A sanitizer that blocks taint flow if the size of a number is limited.
*/
class UpperBoundsCheckSanitizerGuard extends TaintTracking::LabeledSanitizerGuardNode,
DataFlow::ValueNode {
override RelationalComparison astNode;
override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) {
label instanceof Label::Number and
(
true = outcome and
e = astNode.getLesserOperand()
or
false = outcome and
e = astNode.getGreaterOperand()
)
}
}
/**
* A test of form `typeof x === "something"`, preventing `x` from being a number in some cases.
*/
class TypeTestGuard extends TaintTracking::LabeledSanitizerGuardNode, DataFlow::ValueNode {
override EqualityTest astNode;
TypeofExpr typeof;
boolean polarity;
TypeTestGuard() {
astNode.getAnOperand() = typeof and
(
// typeof x === "number" sanitizes `x` when it evaluates to false
astNode.getAnOperand().getStringValue() = "number" and
polarity = astNode.getPolarity().booleanNot()
or
// typeof x === "string" sanitizes `x` when it evaluates to true
astNode.getAnOperand().getStringValue() != "number" and
polarity = astNode.getPolarity()
)
}
override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) {
polarity = outcome and
e = typeof.getOperand() and
label instanceof Label::Number
}
}
/** A source of remote user input, considered as a data flow source for resource exhaustion vulnerabilities. */
class RemoteFlowSourceAsSource extends Source {
RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource }
}
/**
* A node that determines the size of a buffer, considered as a data flow sink for resource exhaustion vulnerabilities.
*/
class BufferSizeSink extends Sink {
BufferSizeSink() {
exists(DataFlow::SourceNode clazz, DataFlow::InvokeNode invk, int index |
clazz = DataFlow::globalVarRef("Buffer") and this = invk.getArgument(index)
|
exists(string name |
invk = clazz.getAMemberCall(name) and
(
name = "from" and index = 2
or
name = ["alloc", "allocUnsafe", "allocUnsafeSlow"] and index = 0
)
)
or
invk = clazz.getAnInvocation() and
(
invk.getNumArgument() = 1 and
index = 0
or
invk.getNumArgument() = 3 and index = 2
)
)
or
this = DataFlow::globalVarRef("SlowBuffer").getAnInstantiation().getArgument(0)
}
override string getProblemDescription() {
result = "This creates a buffer with a user-controlled size"
}
}
/**
* A node that determines the size of an array, considered as a data flow sink for resource exhaustion vulnerabilities.
*/
class DenseArraySizeSink extends Sink {
DenseArraySizeSink() {
// Arrays are sparse by default, so we must also look at how the array is used
exists(DataFlow::ArrayConstructorInvokeNode instance |
this = instance.getArgument(0) and
instance.getNumArgument() = 1
|
exists(instance.getAMethodCall(["map", "fill", "join", "toString"])) or
instance.flowsToExpr(any(AddExpr p).getAnOperand())
)
}
override string getProblemDescription() {
result = "This creates an array with a user-controlled length"
}
}
/**
* A node that determines the repetitions of a string, considered as a data flow sink for resource exhaustion vulnerabilities.
*/
class StringRepetitionSink extends Sink {
StringRepetitionSink() {
exists(DataFlow::MethodCallNode repeat |
repeat.getMethodName() = "repeat" and
this = repeat.getArgument(0)
)
}
override DataFlow::FlowLabel getAFlowLabel() { any() }
override string getProblemDescription() {
result = "This creates a string with a user-controlled length"
}
}
/**
* A node that determines the duration of a timer, considered as a data flow sink for resource exhaustion vulnerabilities.
*/
class TimerDurationSink extends Sink {
TimerDurationSink() {
this = DataFlow::globalVarRef(["setTimeout", "setInterval"]).getACall().getArgument(1) or
this = LodashUnderscore::member(["delay", "throttle", "debounce"]).getACall().getArgument(1)
}
override DataFlow::FlowLabel getAFlowLabel() { any() }
override string getProblemDescription() {
result = "This creates a timer with a user-controlled duration"
}
}
}

View File

@@ -14,3 +14,8 @@
| private-file-exposure.js:18:1:18:74 | app.use ... les"))) | Serves the folder "/node_modules", which can contain private information. |
| private-file-exposure.js:19:1:19:88 | app.use ... lar/')) | Serves the folder "/node_modules/angular/", which can contain private information. |
| private-file-exposure.js:22:1:22:58 | app.use ... lar/')) | Serves the folder "/node_modules/angular/", which can contain private information. |
| private-file-exposure.js:40:1:40:88 | app.use ... lar/')) | Serves the folder "/node_modules/angular/", which can contain private information. |
| private-file-exposure.js:41:1:41:97 | app.use ... lar/')) | Serves the folder "/node_modules/angular/", which can contain private information. |
| private-file-exposure.js:42:1:42:66 | app.use ... dir())) | Serves the home folder , which can contain private information. |
| private-file-exposure.js:43:1:43:46 | app.use ... )("/")) | Serves the root folder, which can contain private information. |
| private-file-exposure.js:51:5:51:88 | app.use ... les'))) | Serves the folder "../node_modules", which can contain private information. |

View File

@@ -35,3 +35,28 @@ app.use('/js/', express.static('node_modules/bootstrap/dist/js'))
app.use('/css/', express.static('node_modules/font-awesome/css'));
app.use('basedir', express.static(__dirname)); // GOOD, because there is no package.json in the same folder.
app.use('/monthly', express.static(__dirname + '/')); // GOOD, because there is no package.json in the same folder.
const connect = require("connect");
app.use('/angular', connect.static(path.join(__dirname, "/node_modules") + '/angular/')); // NOT OK
app.use('/angular', require('serve-static')(path.join(__dirname, "/node_modules") + '/angular/')); // NOT OK
app.use('/home', require('serve-static')(require("os").homedir())); // NOT OK
app.use('/root', require('serve-static')("/")); // NOT OK
// Bad documentation example
function bad() {
var express = require('express');
var app = express();
app.use('/node_modules', express.static(path.resolve(__dirname, '../node_modules'))); // NOT OK
}
// Good documentation example
function good() {
var express = require('express');
var app = express();
app.use("jquery", express.static('./node_modules/jquery/dist')); // OK
app.use("bootstrap", express.static('./node_modules/bootstrap/dist')); // OK
}

View File

@@ -0,0 +1,57 @@
nodes
| build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} |
| build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} |
| build-leaks.js:5:20:5:46 | JSON.st ... ss.env) |
| build-leaks.js:5:35:5:45 | process.env |
| build-leaks.js:5:35:5:45 | process.env |
| build-leaks.js:13:11:19:10 | raw |
| build-leaks.js:13:17:19:10 | Object. ... }) |
| build-leaks.js:14:18:14:20 | env |
| build-leaks.js:15:24:15:34 | process.env |
| build-leaks.js:15:24:15:34 | process.env |
| build-leaks.js:16:20:16:22 | env |
| build-leaks.js:21:11:26:5 | stringifed |
| build-leaks.js:21:24:26:5 | {\\n ... )\\n } |
| build-leaks.js:22:24:25:14 | Object. ... }, {}) |
| build-leaks.js:22:49:22:51 | env |
| build-leaks.js:23:39:23:41 | raw |
| build-leaks.js:24:20:24:22 | env |
| build-leaks.js:30:22:30:31 | stringifed |
| build-leaks.js:34:26:34:57 | getEnv( ... ngified |
| build-leaks.js:34:26:34:57 | getEnv( ... ngified |
| build-leaks.js:40:9:40:60 | pw |
| build-leaks.js:40:14:40:60 | url.par ... assword |
| build-leaks.js:40:14:40:60 | url.par ... assword |
| build-leaks.js:41:43:41:86 | { "proc ... y(pw) } |
| build-leaks.js:41:43:41:86 | { "proc ... y(pw) } |
| build-leaks.js:41:67:41:84 | JSON.stringify(pw) |
| build-leaks.js:41:82:41:83 | pw |
edges
| build-leaks.js:5:20:5:46 | JSON.st ... ss.env) | build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} |
| build-leaks.js:5:20:5:46 | JSON.st ... ss.env) | build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} |
| build-leaks.js:5:35:5:45 | process.env | build-leaks.js:5:20:5:46 | JSON.st ... ss.env) |
| build-leaks.js:5:35:5:45 | process.env | build-leaks.js:5:20:5:46 | JSON.st ... ss.env) |
| build-leaks.js:13:11:19:10 | raw | build-leaks.js:23:39:23:41 | raw |
| build-leaks.js:13:17:19:10 | Object. ... }) | build-leaks.js:13:11:19:10 | raw |
| build-leaks.js:14:18:14:20 | env | build-leaks.js:16:20:16:22 | env |
| build-leaks.js:15:24:15:34 | process.env | build-leaks.js:14:18:14:20 | env |
| build-leaks.js:15:24:15:34 | process.env | build-leaks.js:14:18:14:20 | env |
| build-leaks.js:16:20:16:22 | env | build-leaks.js:13:17:19:10 | Object. ... }) |
| build-leaks.js:21:11:26:5 | stringifed | build-leaks.js:30:22:30:31 | stringifed |
| build-leaks.js:21:24:26:5 | {\\n ... )\\n } | build-leaks.js:21:11:26:5 | stringifed |
| build-leaks.js:22:24:25:14 | Object. ... }, {}) | build-leaks.js:21:24:26:5 | {\\n ... )\\n } |
| build-leaks.js:22:49:22:51 | env | build-leaks.js:24:20:24:22 | env |
| build-leaks.js:23:39:23:41 | raw | build-leaks.js:22:49:22:51 | env |
| build-leaks.js:24:20:24:22 | env | build-leaks.js:22:24:25:14 | Object. ... }, {}) |
| build-leaks.js:30:22:30:31 | stringifed | build-leaks.js:34:26:34:57 | getEnv( ... ngified |
| build-leaks.js:30:22:30:31 | stringifed | build-leaks.js:34:26:34:57 | getEnv( ... ngified |
| build-leaks.js:40:9:40:60 | pw | build-leaks.js:41:82:41:83 | pw |
| build-leaks.js:40:14:40:60 | url.par ... assword | build-leaks.js:40:9:40:60 | pw |
| build-leaks.js:40:14:40:60 | url.par ... assword | build-leaks.js:40:9:40:60 | pw |
| build-leaks.js:41:67:41:84 | JSON.stringify(pw) | build-leaks.js:41:43:41:86 | { "proc ... y(pw) } |
| build-leaks.js:41:67:41:84 | JSON.stringify(pw) | build-leaks.js:41:43:41:86 | { "proc ... y(pw) } |
| build-leaks.js:41:82:41:83 | pw | build-leaks.js:41:67:41:84 | JSON.stringify(pw) |
#select
| build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} | build-leaks.js:5:35:5:45 | process.env | build-leaks.js:4:39:6:1 | { // NO ... .env)\\n} | Sensitive data returned by $@ is stored in a build artifact here. | build-leaks.js:5:35:5:45 | process.env | process environment |
| build-leaks.js:34:26:34:57 | getEnv( ... ngified | build-leaks.js:15:24:15:34 | process.env | build-leaks.js:34:26:34:57 | getEnv( ... ngified | Sensitive data returned by $@ is stored in a build artifact here. | build-leaks.js:15:24:15:34 | process.env | process environment |
| build-leaks.js:41:43:41:86 | { "proc ... y(pw) } | build-leaks.js:40:14:40:60 | url.par ... assword | build-leaks.js:41:43:41:86 | { "proc ... y(pw) } | Sensitive data returned by $@ is stored in a build artifact here. | build-leaks.js:40:14:40:60 | url.par ... assword | an access to current_password |

View File

@@ -0,0 +1 @@
Security/CWE-312/BuildArtifactLeak.ql

View File

@@ -0,0 +1,42 @@
const webpack = require("webpack");
var plugin = new webpack.DefinePlugin({ // NOT OK
"process.env": JSON.stringify(process.env)
});
// OK
new webpack.DefinePlugin({ 'process.env': JSON.stringify({ DEBUG: process.env.DEBUG }) })
function getEnv(env) {
const raw = Object.keys(process.env)
.reduce((env, key) => {
env[key] = process.env[key]
return env
}, {
NODE_ENV: process.env.NODE_ENV || env || 'development'
})
const stringifed = {
'process.env': Object.keys(raw).reduce((env, key) => {
env[key] = JSON.stringify(raw[key])
return env
}, {})
}
return {
raw: raw,
stringified: stringifed
}
}
new webpack.DefinePlugin(getEnv('production').stringified); // NOT OK
var https = require('https');
var url = require('url');
var server = https.createServer(function (req, res) {
let pw = url.parse(req.url, true).query.current_password;
var plugin = new webpack.DefinePlugin({ "process.env.secret": JSON.stringify(pw) }); // NOT OK
});

View File

@@ -13,3 +13,6 @@
| bad-random.js:85:11:85:35 | goodRan ... Random2 | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically secure random number |
| bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:83:23:83:38 | secureRandom(10) | cryptographically secure random number |
| bad-random.js:87:16:87:24 | bad + bad | Using addition on a $@ produces biased results. | bad-random.js:84:23:84:38 | secureRandom(10) | cryptographically secure random number |
| bad-random.js:90:29:90:54 | secureR ... / 25.6 | Using division and rounding the result on a $@ produces biased results. | bad-random.js:90:29:90:44 | secureRandom(10) | cryptographically secure random number |
| bad-random.js:96:29:96:58 | crypto. ... ] / 100 | Using division and rounding the result on a $@ produces biased results. | bad-random.js:96:29:96:49 | crypto. ... ytes(1) | cryptographically secure random number |
| bad-random.js:118:17:118:45 | crypto. ... 0] % 10 | Using modulo on a $@ produces biased results. | bad-random.js:118:17:118:37 | crypto. ... ytes(1) | cryptographically secure random number |

View File

@@ -87,13 +87,13 @@ var bad = goodRandom1 + goodRandom2; // NOT OK
var dontFlag = bad + bad; // OK - the operands have already been flagged - but flagged anyway due to us not detecting that [INCONSISTENCY].
var good = secureRandom(10)[0] / 0xff; // OK - result is not rounded.
var good = Math.ceil(0.5 - (secureRandom(10)[0] / 25.6)); // NOT OK - division generally introduces bias - but not flagged due to not looking through nested arithmetic [INCONSISTENCY].
var good = Math.ceil(0.5 - (secureRandom(10)[0] / 25.6)); // NOT OK - division generally introduces bias - but not flagged due to not looking through nested arithmetic.
var good = (crypto.randomBytes(1)[0] << 8) + crypto.randomBytes(3)[0]; // OK - bit shifts are usually used to construct larger/smaller numbers,
var good = Math.floor(max * (crypto.randomBytes(1)[0] / 0xff)); // OK - division by 0xff (255) gives a uniformly random number between 0 and 1.
var bad = Math.floor(max * (crypto.randomBytes(1)[0] / 100)); // NOT OK - division by 100 gives bias - but not flagged due to not looking through nested arithmetic [INCONSISTENCY].
var bad = Math.floor(max * (crypto.randomBytes(1)[0] / 100)); // NOT OK - division by 100 gives bias - but not flagged due to not looking through nested arithmetic.
var crb = crypto.randomBytes(4);
var cryptoRand = 0x01000000 * crb[0] + 0x00010000 * crb[1] + 0x00000100 * crb[2] + 0x00000001 * crb[3]; // OK - producing a larger number from smaller numbers.
@@ -110,4 +110,20 @@ var a = crypto.randomBytes(10);
var good = ((a[i] & 31) * 0x1000000000000) + (a[i + 1] * 0x10000000000) + (a[i + 2] * 0x100000000) + (a[i + 3] * 0x1000000) + (a[i + 4] << 16) + (a[i + 5] << 8) + a[i + 6]; // OK - generating a large number from smaller bytes.
var good = (a[i] * 0x100000000) + a[i + 6]; // OK - generating a large number from smaller bytes.
var good = (a[i + 2] * 0x10000000) + a[i + 6]; // OK - generating a large number from smaller bytes.
var foo = 0xffffffffffff + 0xfffffffffff + 0xffffffffff + 0xfffffffff + 0xffffffff + 0xfffffff + 0xffffff
var foo = 0xffffffffffff + 0xfffffffffff + 0xffffffffff + 0xfffffffff + 0xffffffff + 0xfffffff + 0xffffff
// Bad documentation example:
const digits = [];
for (let i = 0; i < 10; i++) {
digits.push(crypto.randomBytes(1)[0] % 10); // NOT OK
}
// Good documentation example:
const digits = [];
while (digits.length < 10) {
const byte = crypto.randomBytes(1)[0];
if (byte >= 250) {
continue;
}
digits.push(byte % 10); // OK
}

View File

@@ -0,0 +1,234 @@
nodes
| documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size |
| documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) |
| documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) |
| documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query |
| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size |
| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size |
| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url |
| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url |
| documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size |
| documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size |
| documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size |
| documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) |
| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) |
| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query |
| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size |
| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size |
| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url |
| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url |
| documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size |
| documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size |
| documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay |
| documentation_examples/ResourceExhaustion_timeout.js:5:14:5:59 | parseIn ... .delay) |
| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) |
| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:52 | url.par ... ).query |
| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:58 | url.par ... y.delay |
| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url |
| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url |
| documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay |
| documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay |
| resource-exhaustion.js:5:7:5:42 | s |
| resource-exhaustion.js:5:11:5:34 | url.par ... , true) |
| resource-exhaustion.js:5:11:5:40 | url.par ... ).query |
| resource-exhaustion.js:5:11:5:42 | url.par ... query.s |
| resource-exhaustion.js:5:21:5:27 | req.url |
| resource-exhaustion.js:5:21:5:27 | req.url |
| resource-exhaustion.js:6:7:6:21 | n |
| resource-exhaustion.js:6:11:6:21 | parseInt(s) |
| resource-exhaustion.js:6:20:6:20 | s |
| resource-exhaustion.js:12:21:12:21 | n |
| resource-exhaustion.js:12:21:12:21 | n |
| resource-exhaustion.js:13:21:13:21 | n |
| resource-exhaustion.js:13:21:13:21 | n |
| resource-exhaustion.js:14:16:14:16 | n |
| resource-exhaustion.js:14:16:14:16 | n |
| resource-exhaustion.js:15:22:15:22 | n |
| resource-exhaustion.js:15:22:15:22 | n |
| resource-exhaustion.js:16:26:16:26 | n |
| resource-exhaustion.js:16:26:16:26 | n |
| resource-exhaustion.js:18:14:18:14 | n |
| resource-exhaustion.js:18:14:18:14 | n |
| resource-exhaustion.js:20:20:20:20 | n |
| resource-exhaustion.js:20:20:20:20 | n |
| resource-exhaustion.js:22:18:22:18 | n |
| resource-exhaustion.js:22:18:22:18 | n |
| resource-exhaustion.js:27:9:27:9 | n |
| resource-exhaustion.js:27:9:27:9 | n |
| resource-exhaustion.js:28:13:28:13 | n |
| resource-exhaustion.js:28:13:28:13 | n |
| resource-exhaustion.js:29:9:29:9 | n |
| resource-exhaustion.js:29:9:29:9 | n |
| resource-exhaustion.js:30:9:30:9 | n |
| resource-exhaustion.js:30:9:30:9 | n |
| resource-exhaustion.js:31:9:31:9 | n |
| resource-exhaustion.js:31:9:31:9 | n |
| resource-exhaustion.js:32:9:32:9 | n |
| resource-exhaustion.js:32:9:32:9 | n |
| resource-exhaustion.js:34:12:34:12 | n |
| resource-exhaustion.js:34:12:34:12 | n |
| resource-exhaustion.js:35:12:35:12 | s |
| resource-exhaustion.js:35:12:35:12 | s |
| resource-exhaustion.js:37:14:37:14 | n |
| resource-exhaustion.js:37:14:37:18 | n * x |
| resource-exhaustion.js:37:14:37:18 | n * x |
| resource-exhaustion.js:45:14:45:25 | Math.ceil(s) |
| resource-exhaustion.js:45:14:45:25 | Math.ceil(s) |
| resource-exhaustion.js:45:24:45:24 | s |
| resource-exhaustion.js:46:14:46:22 | Number(s) |
| resource-exhaustion.js:46:14:46:22 | Number(s) |
| resource-exhaustion.js:46:21:46:21 | s |
| resource-exhaustion.js:50:14:50:14 | s |
| resource-exhaustion.js:50:14:50:21 | s.length |
| resource-exhaustion.js:50:14:50:21 | s.length |
| resource-exhaustion.js:55:16:55:16 | n |
| resource-exhaustion.js:55:16:55:16 | n |
| resource-exhaustion.js:58:7:58:20 | ns |
| resource-exhaustion.js:58:12:58:20 | x ? n : s |
| resource-exhaustion.js:58:16:58:16 | n |
| resource-exhaustion.js:59:14:59:15 | ns |
| resource-exhaustion.js:59:14:59:15 | ns |
| resource-exhaustion.js:66:16:66:16 | n |
| resource-exhaustion.js:66:16:66:16 | n |
| resource-exhaustion.js:70:16:70:16 | n |
| resource-exhaustion.js:70:16:70:16 | n |
| resource-exhaustion.js:81:17:81:17 | n |
| resource-exhaustion.js:81:17:81:17 | n |
| resource-exhaustion.js:82:17:82:17 | s |
| resource-exhaustion.js:82:17:82:17 | s |
| resource-exhaustion.js:83:18:83:18 | n |
| resource-exhaustion.js:83:18:83:18 | n |
| resource-exhaustion.js:84:18:84:18 | s |
| resource-exhaustion.js:84:18:84:18 | s |
edges
| documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size |
| documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size |
| documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) | documentation_examples/ResourceExhaustion_array.js:5:6:5:57 | size |
| documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) | documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query |
| documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size |
| documentation_examples/ResourceExhaustion_array.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size |
| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) |
| documentation_examples/ResourceExhaustion_array.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_array.js:5:13:5:57 | parseIn ... y.size) |
| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) |
| documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_array.js:5:22:5:45 | url.par ... , true) |
| documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size |
| documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size | documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size |
| documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) | documentation_examples/ResourceExhaustion_buffer.js:5:6:5:57 | size |
| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query |
| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size |
| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:51 | url.par ... ).query | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size |
| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) |
| documentation_examples/ResourceExhaustion_buffer.js:5:22:5:56 | url.par ... ry.size | documentation_examples/ResourceExhaustion_buffer.js:5:13:5:57 | parseIn ... y.size) |
| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) |
| documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_buffer.js:5:22:5:45 | url.par ... , true) |
| documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay | documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay |
| documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay | documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay |
| documentation_examples/ResourceExhaustion_timeout.js:5:14:5:59 | parseIn ... .delay) | documentation_examples/ResourceExhaustion_timeout.js:5:6:5:59 | delay |
| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:52 | url.par ... ).query |
| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:52 | url.par ... ).query | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:58 | url.par ... y.delay |
| documentation_examples/ResourceExhaustion_timeout.js:5:23:5:58 | url.par ... y.delay | documentation_examples/ResourceExhaustion_timeout.js:5:14:5:59 | parseIn ... .delay) |
| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) |
| documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentation_examples/ResourceExhaustion_timeout.js:5:23:5:46 | url.par ... , true) |
| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:6:20:6:20 | s |
| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:35:12:35:12 | s |
| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:35:12:35:12 | s |
| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:45:24:45:24 | s |
| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:46:21:46:21 | s |
| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:50:14:50:14 | s |
| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:82:17:82:17 | s |
| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:82:17:82:17 | s |
| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:84:18:84:18 | s |
| resource-exhaustion.js:5:7:5:42 | s | resource-exhaustion.js:84:18:84:18 | s |
| resource-exhaustion.js:5:11:5:34 | url.par ... , true) | resource-exhaustion.js:5:11:5:40 | url.par ... ).query |
| resource-exhaustion.js:5:11:5:40 | url.par ... ).query | resource-exhaustion.js:5:11:5:42 | url.par ... query.s |
| resource-exhaustion.js:5:11:5:42 | url.par ... query.s | resource-exhaustion.js:5:7:5:42 | s |
| resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:5:11:5:34 | url.par ... , true) |
| resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:5:11:5:34 | url.par ... , true) |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:12:21:12:21 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:12:21:12:21 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:13:21:13:21 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:13:21:13:21 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:14:16:14:16 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:14:16:14:16 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:15:22:15:22 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:15:22:15:22 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:16:26:16:26 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:16:26:16:26 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:18:14:18:14 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:18:14:18:14 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:20:20:20:20 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:20:20:20:20 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:22:18:22:18 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:22:18:22:18 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:27:9:27:9 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:27:9:27:9 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:28:13:28:13 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:28:13:28:13 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:29:9:29:9 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:29:9:29:9 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:30:9:30:9 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:30:9:30:9 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:31:9:31:9 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:31:9:31:9 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:32:9:32:9 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:32:9:32:9 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:34:12:34:12 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:34:12:34:12 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:37:14:37:14 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:55:16:55:16 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:55:16:55:16 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:58:16:58:16 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:66:16:66:16 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:66:16:66:16 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:70:16:70:16 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:70:16:70:16 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:81:17:81:17 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:81:17:81:17 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:83:18:83:18 | n |
| resource-exhaustion.js:6:7:6:21 | n | resource-exhaustion.js:83:18:83:18 | n |
| resource-exhaustion.js:6:11:6:21 | parseInt(s) | resource-exhaustion.js:6:7:6:21 | n |
| resource-exhaustion.js:6:20:6:20 | s | resource-exhaustion.js:6:11:6:21 | parseInt(s) |
| resource-exhaustion.js:37:14:37:14 | n | resource-exhaustion.js:37:14:37:18 | n * x |
| resource-exhaustion.js:37:14:37:14 | n | resource-exhaustion.js:37:14:37:18 | n * x |
| resource-exhaustion.js:45:24:45:24 | s | resource-exhaustion.js:45:14:45:25 | Math.ceil(s) |
| resource-exhaustion.js:45:24:45:24 | s | resource-exhaustion.js:45:14:45:25 | Math.ceil(s) |
| resource-exhaustion.js:46:21:46:21 | s | resource-exhaustion.js:46:14:46:22 | Number(s) |
| resource-exhaustion.js:46:21:46:21 | s | resource-exhaustion.js:46:14:46:22 | Number(s) |
| resource-exhaustion.js:50:14:50:14 | s | resource-exhaustion.js:50:14:50:21 | s.length |
| resource-exhaustion.js:50:14:50:14 | s | resource-exhaustion.js:50:14:50:21 | s.length |
| resource-exhaustion.js:58:7:58:20 | ns | resource-exhaustion.js:59:14:59:15 | ns |
| resource-exhaustion.js:58:7:58:20 | ns | resource-exhaustion.js:59:14:59:15 | ns |
| resource-exhaustion.js:58:12:58:20 | x ? n : s | resource-exhaustion.js:58:7:58:20 | ns |
| resource-exhaustion.js:58:16:58:16 | n | resource-exhaustion.js:58:12:58:20 | x ? n : s |
#select
| documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_array.js:7:23:7:26 | size | This creates an array with a user-controlled length from $@. | documentation_examples/ResourceExhaustion_array.js:5:32:5:38 | req.url | here |
| documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | documentation_examples/ResourceExhaustion_buffer.js:7:28:7:31 | size | This creates a buffer with a user-controlled size from $@. | documentation_examples/ResourceExhaustion_buffer.js:5:32:5:38 | req.url | here |
| documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | documentation_examples/ResourceExhaustion_timeout.js:7:16:7:20 | delay | This creates a timer with a user-controlled duration from $@. | documentation_examples/ResourceExhaustion_timeout.js:5:33:5:39 | req.url | here |
| resource-exhaustion.js:12:21:12:21 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:12:21:12:21 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:13:21:13:21 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:13:21:13:21 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:14:16:14:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:14:16:14:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:15:22:15:22 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:15:22:15:22 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:16:26:16:26 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:16:26:16:26 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:18:14:18:14 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:18:14:18:14 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:20:20:20:20 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:20:20:20:20 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:22:18:22:18 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:22:18:22:18 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:27:9:27:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:27:9:27:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:28:13:28:13 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:28:13:28:13 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:29:9:29:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:29:9:29:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:30:9:30:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:30:9:30:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:31:9:31:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:31:9:31:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:32:9:32:9 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:32:9:32:9 | n | This creates an array with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:34:12:34:12 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:34:12:34:12 | n | This creates a string with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:35:12:35:12 | s | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:35:12:35:12 | s | This creates a string with a user-controlled length from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:37:14:37:18 | n * x | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:37:14:37:18 | n * x | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:45:14:45:25 | Math.ceil(s) | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:46:14:46:22 | Number(s) | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:46:14:46:22 | Number(s) | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:50:14:50:21 | s.length | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:50:14:50:21 | s.length | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:55:16:55:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:55:16:55:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:59:14:59:15 | ns | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:59:14:59:15 | ns | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:66:16:66:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:66:16:66:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:70:16:70:16 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:70:16:70:16 | n | This creates a buffer with a user-controlled size from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:81:17:81:17 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:81:17:81:17 | n | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:82:17:82:17 | s | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:82:17:82:17 | s | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:83:18:83:18 | n | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:83:18:83:18 | n | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |
| resource-exhaustion.js:84:18:84:18 | s | resource-exhaustion.js:5:21:5:27 | req.url | resource-exhaustion.js:84:18:84:18 | s | This creates a timer with a user-controlled duration from $@. | resource-exhaustion.js:5:21:5:27 | req.url | here |

View File

@@ -0,0 +1 @@
Security/CWE-770/ResourceExhaustion.ql

View File

@@ -0,0 +1,10 @@
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
var size = parseInt(url.parse(req.url, true).query.size);
let dogs = new Array(size).fill(x => "dog"); // BAD
// ... use the dog
});

View File

@@ -0,0 +1,16 @@
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
var size = parseInt(url.parse(req.url, true).query.size);
if (size > 1024) {
res.statusCode = 400;
res.end("Bad request.");
return;
}
let dogs = new Array(size).fill(x => "dog"); // GOOD
// ... use the dogs
});

View File

@@ -0,0 +1,10 @@
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
var size = parseInt(url.parse(req.url, true).query.size);
let buffer = Buffer.alloc(size); // BAD
// ... use the buffer
});

View File

@@ -0,0 +1,16 @@
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
var size = parseInt(url.parse(req.url, true).query.size);
if (size > 1024) {
res.statusCode = 400;
res.end("Bad request.");
return;
}
let buffer = Buffer.alloc(size); // GOOD
// ... use the buffer
});

View File

@@ -0,0 +1,9 @@
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
var delay = parseInt(url.parse(req.url, true).query.delay);
setTimeout(f, delay); // BAD
});

View File

@@ -0,0 +1,15 @@
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
var delay = parseInt(url.parse(req.url, true).query.delay);
if (delay > 1000) {
res.statusCode = 400;
res.end("Bad request.");
return;
}
setTimeout(f, delay); // GOOD
});

View File

@@ -0,0 +1,85 @@
var http = require("http"),
url = require("url");
var server = http.createServer(function(req, res) {
let s = url.parse(req.url, true).query.s;
let n = parseInt(s);
Buffer.from(s); // OK
Buffer.from(n); // OK
Buffer.from(x, n); // OK
Buffer.from(x, y, s); // NOT OK
Buffer.from(x, y, n); // NOT OK
Buffer.from(x, y, n); // NOT OK
Buffer.alloc(n); // NOT OK
Buffer.allocUnsafe(n); // NOT OK
Buffer.allocUnsafeSlow(n); // NOT OK
new Buffer(n); // NOT OK
new Buffer(x, n); // OK
new Buffer(x, y, n); // NOT OK
new SlowBuffer(n); // NOT OK
Array(n); // OK
new Array(n); // OK
Array(n).map(); // NOT OK
new Array(n).map(); // NOT OK
Array(n).fill(); // NOT OK
Array(n).join(); // NOT OK
Array(n).toString(); // NOT OK
Array(n) + x; // NOT OK
x.repeat(n); // NOT OK
x.repeat(s); // NOT OK
new Buffer(n * x); // NOT OK
new Buffer(n + n); // NOT OK [INCONSISTENCY]
new Buffer(n + x); // OK (maybe)
new Buffer(n + s); // OK (this is a string if `s` is a string)
new Buffer(s + 2); // OK (this is a string if `s` is a string)
new Buffer(s + s); // OK
new Buffer(n + "X"); // OK
new Buffer(Math.ceil(s)); // NOT OK
new Buffer(Number(s)); // NOT OK
new Buffer(new Number(s)); // OK
new Buffer(s + x.length); // OK (this is a string if `s` is a string)
new Buffer(s.length); // NOT OK
if (n < 100) {
new Buffer(n); // OK
} else {
new Buffer(n); // NOT OK
}
let ns = x ? n : s;
new Buffer(ns); // NOT OK
new Buffer(n.toString()); // OK
if (typeof n === "string") {
new Buffer(n); // OK
} else {
new Buffer(n); // NOT OK
}
if (typeof n === "number") {
new Buffer(n); // NOT OK
} else {
new Buffer(n); // OK
}
if (typeof s === "number") {
new Buffer(s); // NOT OK [INCONSISTENCY]
} else {
new Buffer(s); // OK
}
setTimeout(f, n); // NOT OK
setTimeout(f, s); // NOT OK
setInterval(f, n); // NOT OK
setInterval(f, s); // NOT OK
});

View File

@@ -0,0 +1,38 @@
nodes
| insecure-download.js:5:16:5:28 | installer.url |
| insecure-download.js:5:16:5:28 | installer.url |
| insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' |
| insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' |
| insecure-download.js:15:18:15:40 | buildTo ... llerUrl |
| insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" |
| insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" |
| insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" |
| insecure-download.js:36:9:36:45 | url |
| insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" |
| insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" |
| insecure-download.js:37:23:37:25 | url |
| insecure-download.js:37:23:37:25 | url |
| insecure-download.js:39:26:39:28 | url |
| insecure-download.js:39:26:39:28 | url |
| insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" |
| insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" |
| insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" |
edges
| insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | insecure-download.js:15:18:15:40 | buildTo ... llerUrl |
| insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | insecure-download.js:15:18:15:40 | buildTo ... llerUrl |
| insecure-download.js:15:18:15:40 | buildTo ... llerUrl | insecure-download.js:5:16:5:28 | installer.url |
| insecure-download.js:15:18:15:40 | buildTo ... llerUrl | insecure-download.js:5:16:5:28 | installer.url |
| insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" |
| insecure-download.js:36:9:36:45 | url | insecure-download.js:37:23:37:25 | url |
| insecure-download.js:36:9:36:45 | url | insecure-download.js:37:23:37:25 | url |
| insecure-download.js:36:9:36:45 | url | insecure-download.js:39:26:39:28 | url |
| insecure-download.js:36:9:36:45 | url | insecure-download.js:39:26:39:28 | url |
| insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:36:9:36:45 | url |
| insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:36:9:36:45 | url |
| insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" |
#select
| insecure-download.js:5:16:5:28 | installer.url | insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | insecure-download.js:5:16:5:28 | installer.url | $@ of sensitive file from $@. | insecure-download.js:5:9:5:44 | nugget( ... => { }) | Download | insecure-download.js:9:27:9:138 | 'http:/ ... ll.exe' | HTTP source |
| insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | $@ of sensitive file from $@. | insecure-download.js:30:5:30:43 | nugget( ... e.APK") | Download | insecure-download.js:30:12:30:42 | "http:/ ... fe.APK" | HTTP source |
| insecure-download.js:37:23:37:25 | url | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:37:23:37:25 | url | $@ of sensitive file from $@. | insecure-download.js:37:5:37:42 | cp.exec ... () {}) | Download | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source |
| insecure-download.js:39:26:39:28 | url | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | insecure-download.js:39:26:39:28 | url | $@ of sensitive file from $@. | insecure-download.js:39:5:39:46 | cp.exec ... () {}) | Download | insecure-download.js:36:15:36:45 | "http:/ ... fe.APK" | HTTP source |
| insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | $@ of sensitive file from $@. | insecure-download.js:41:5:41:42 | nugget( ... e.APK") | Download | insecure-download.js:41:12:41:41 | "ftp:// ... fe.APK" | HTTP source |

View File

@@ -0,0 +1 @@
Security/CWE-829/InsecureDownload.ql

View File

@@ -0,0 +1,42 @@
const nugget = require('nugget');
function foo() {
function downloadTools(installer) {
nugget(installer.url, {}, () => { }) // NOT OK
}
var constants = {
buildTools: {
installerUrl: 'http://download.microsoft.com/download/5/f/7/5f7acaeb-8363-451f-9425-68a90f98b238/visualcppbuildtools_full.exe'
}
}
function getBuildToolsInstallerPath() {
const buildTools = constants.buildTools
return {
url: buildTools.installerUrl
}
}
downloadTools(getBuildToolsInstallerPath())
}
const request = require('request');
function bar() {
request('http://www.google.com', function () { }); // OK
nugget("https://download.microsoft.com/download/5/f/7/5f7acaeb-8363-451f-9425-68a90f98b238/visualcppbuildtools_full.exe") // OK
nugget("http://example.org/unsafe.APK") // NOT OK
}
var cp = require("child_process")
function baz() {
var url = "http://example.org/unsafe.APK";
cp.exec("curl " + url, function () {}); // NOT OK
cp.execFile("curl", [url], function () {}); // NOT OK
nugget("ftp://example.org/unsafe.APK") // NOT OK
}