mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Merge branch 'js-team-sprint' into js/insecure-http-options
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
var express = require('express');
|
||||
|
||||
var app = express();
|
||||
|
||||
app.use('/node_modules', express.static(path.resolve(__dirname, '../node_modules')));
|
||||
@@ -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'));
|
||||
36
javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp
Normal file
36
javascript/ql/src/Security/CWE-312/BuildArtifactLeak.qhelp
Normal 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>
|
||||
23
javascript/ql/src/Security/CWE-312/BuildArtifactLeak.ql
Normal file
23
javascript/ql/src/Security/CWE-312/BuildArtifactLeak.ql
Normal 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()
|
||||
@@ -0,0 +1,9 @@
|
||||
const webpack = require("webpack");
|
||||
|
||||
module.exports = [{
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': JSON.stringify({ DEBUG: process.env.DEBUG })
|
||||
})
|
||||
]
|
||||
}];
|
||||
@@ -0,0 +1,9 @@
|
||||
const webpack = require("webpack");
|
||||
|
||||
module.exports = [{
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
"process.env": JSON.stringify(process.env)
|
||||
})
|
||||
]
|
||||
}];
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
const cryptoRandomString = require('crypto-random-string');
|
||||
|
||||
const digits = cryptoRandomString({length: 10, type: 'numeric'});
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
113
javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp
Normal file
113
javascript/ql/src/Security/CWE-770/ResourceExhaustion.qhelp
Normal 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>
|
||||
20
javascript/ql/src/Security/CWE-770/ResourceExhaustion.ql
Normal file
20
javascript/ql/src/Security/CWE-770/ResourceExhaustion.ql
Normal 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"
|
||||
@@ -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
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
@@ -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
|
||||
|
||||
});
|
||||
@@ -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
|
||||
|
||||
});
|
||||
38
javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp
Normal file
38
javascript/ql/src/Security/CWE-829/InsecureDownload.qhelp
Normal 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>
|
||||
20
javascript/ql/src/Security/CWE-829/InsecureDownload.ql
Normal file
20
javascript/ql/src/Security/CWE-829/InsecureDownload.ql
Normal 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"
|
||||
@@ -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));
|
||||
@@ -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));
|
||||
@@ -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
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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. |
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE-312/BuildArtifactLeak.ql
|
||||
@@ -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
|
||||
});
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE-770/ResourceExhaustion.ql
|
||||
@@ -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
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
@@ -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
|
||||
|
||||
});
|
||||
@@ -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
|
||||
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
@@ -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 |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE-829/InsecureDownload.ql
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user