Skip to content

Commit 0654823

Browse files
authored
Merge branch 'js-team-sprint' into js/insecure-http-options
2 parents f1dad0d + eca5e2d commit 0654823

File tree

56 files changed

+1645
-56
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1645
-56
lines changed

change-notes/1.25/analysis-javascript.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@
3636
| Incomplete HTML attribute sanitization (`js/incomplete-html-attribute-sanitization`) | security, external/cwe/cwe-20, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities due to incomplete sanitization of HTML meta-characters. Results are shown on LGTM by default. |
3737
| Unsafe expansion of self-closing HTML tag (`js/unsafe-html-expansion`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights potential XSS vulnerabilities caused by unsafe expansion of self-closing HTML tags. |
3838
| Unsafe shell command constructed from library input (`js/shell-command-constructed-from-input`) | correctness, security, external/cwe/cwe-078, external/cwe/cwe-088 | Highlights potential command injections due to a shell command being constructed from library inputs. Results are shown on LGTM by default. |
39+
| Download of sensitive file through insecure connection (`js/insecure-download`) | security, external/cwe/cwe-829 | Highlights downloads of sensitive files through an unencrypted protocol. Results are shown on LGTM by default. |
40+
| Exposure of private files (`js/exposure-of-private-files`) | security, external/cwe/cwe-200 | Highlights servers that serve private files. Results are shown on LGTM by default. |
41+
| Creating biased random numbers from a cryptographically secure source (`js/biased-cryptographic-random`) | security, external/cwe/cwe-327 | Highlights mathematical operations on cryptographically secure numbers that can create biased results. Results are shown on LGTM by default. |
42+
| Storage of sensitive information in build artifact (`js/build-artifact-leak`) | security, external/cwe/cwe-312 | Highlights storage of sensitive information in build artifacts. Results are shown on LGTM by default. |
3943
| Improper code sanitization (`js/bad-code-sanitization`) | security, external/cwe/cwe-094, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights string concatenation where code is constructed without proper sanitization. Results are shown on LGTM by default. |
44+
| Resource exhaustion (`js/resource-exhaustion`) | security, external/cwe/cwe-770 | Highlights operations that may cause the resources of the application to be exhausted. Results are shown on LGTM by default. |
4045
| Disabling certificate validation (`js/disabling-certificate-validation`) | security, external/cwe-295 | Highlights locations where SSL certificate validation is disabled. Results are shown on LGTM by default. |
4146

4247
## Changes to existing queries

javascript/config/suites/javascript/security

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
+ semmlecode-javascript-queries/Security/CWE-730/RegExpInjection.ql: /Security/CWE/CWE-730
4646
+ semmlecode-javascript-queries/Security/CWE-754/UnvalidatedDynamicMethodCall.ql: /Security/CWE/CWE-754
4747
+ semmlecode-javascript-queries/Security/CWE-770/MissingRateLimiting.ql: /Security/CWE/CWE-770
48+
+ semmlecode-javascript-queries/Security/CWE-770/ResourceExhaustion.ql: /Security/CWE/CWE-770
4849
+ semmlecode-javascript-queries/Security/CWE-776/XmlBomb.ql: /Security/CWE/CWE-776
4950
+ semmlecode-javascript-queries/Security/CWE-798/HardcodedCredentials.ql: /Security/CWE/CWE-798
5051
+ semmlecode-javascript-queries/Security/CWE-807/ConditionalBypass.ql: /Security/CWE/CWE-807

javascript/ql/src/Security/CWE-200/PrivateFileExposure.qhelp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,33 @@
55

66
<overview>
77
<p>
8-
Placeholder
8+
Libraries like <code>express</code> provide easy methods for serving entire
9+
directories of static files from a web server.
10+
However, using these can sometimes lead to accidental information exposure.
11+
If for example the <code>node_modules</code> folder is served, then an attacker
12+
can access the <code>_where</code> field from a <code>package.json</code> file,
13+
which gives access to the absolute path of the file.
914
</p>
1015
</overview>
1116

1217
<recommendation>
1318
<p>
14-
Placeholder
19+
Limit which folders of static files are served from a web server.
1520
</p>
1621
</recommendation>
1722

1823
<example>
1924
<p>
20-
Placeholder
25+
In the example below, all the files from the <code>node_modules</code> are served.
26+
This allows clients to easily access all the files inside that folder,
27+
which includes potentially private information inside <code>package.json</code> files.
2128
</p>
29+
<sample src="examples/PrivateFileExposure.js"/>
30+
<p>
31+
The issue has been fixed below by only serving specific folders within the
32+
<code>node_modules</code> folder.
33+
</p>
34+
<sample src="examples/PrivateFileExposureFixed.js"/>
2235
</example>
2336

2437
<references>

javascript/ql/src/Security/CWE-200/PrivateFileExposure.ql

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -69,19 +69,33 @@ pragma[noinline]
6969
Folder getAPackageJSONFolder() { result = any(PackageJSON json).getFile().getParentContainer() }
7070

7171
/**
72-
* Gets a reference to `dirname` that might cause information to be leaked.
73-
* That can happen if there is a `package.json` file in the same folder.
74-
* (It is assumed that the presence of a `package.json` file means that a `node_modules` folder can also exist.
72+
* Gets a reference to `dirname`, the home folder, the current working folder, or the root folder.
73+
* All of these might cause information to be leaked.
74+
*
75+
* For `dirname` that can happen if there is a `package.json` file in the same folder.
76+
* It is assumed that the presence of a `package.json` file means that a `node_modules` folder can also exist.
77+
*
78+
* 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).
7579
*/
76-
DataFlow::Node dirname() {
80+
DataFlow::Node getALeakingFolder(string description) {
7781
exists(ModuleScope ms | result.asExpr() = ms.getVariable("__dirname").getAnAccess()) and
78-
result.getFile().getParentContainer() = getAPackageJSONFolder()
82+
result.getFile().getParentContainer() = getAPackageJSONFolder() and
83+
description = "the folder " + result.getFile().getParentContainer().getRelativePath()
84+
or
85+
result = DataFlow::moduleImport("os").getAMemberCall("homedir") and
86+
description = "the home folder "
87+
or
88+
result.mayHaveStringValue("/") and
89+
description = "the root folder"
90+
or
91+
result.getStringValue() = [".", "./"] and
92+
description = "the current working folder"
7993
or
80-
result.getAPredecessor() = dirname()
94+
result.getAPredecessor() = getALeakingFolder(description)
8195
or
8296
exists(StringOps::ConcatenationRoot root | root = result |
8397
root.getNumOperand() = 2 and
84-
root.getOperand(0) = dirname() and
98+
root.getOperand(0) = getALeakingFolder(description) and
8599
root.getOperand(1).getStringValue() = "/"
86100
)
87101
}
@@ -94,18 +108,17 @@ DataFlow::Node getAPrivateFolderPath(string description) {
94108
result = getANodeModulePath(path) and description = "the folder \"" + path + "\""
95109
)
96110
or
97-
result = dirname() and
98-
description = "the folder " + result.getFile().getParentContainer().getRelativePath()
99-
or
100-
result.getStringValue() = [".", "./"] and
101-
description = "the current working folder"
111+
result = getALeakingFolder(description)
102112
}
103113

104114
/**
105115
* Gest a call that serves the folder `path` to the public.
106116
*/
107117
DataFlow::CallNode servesAPrivateFolder(string description) {
108-
result = DataFlow::moduleMember("express", "static").getACall() and
118+
result = DataFlow::moduleMember(["express", "connect"], "static").getACall() and
119+
result.getArgument(0) = getAPrivateFolderPath(description)
120+
or
121+
result = DataFlow::moduleImport("serve-static").getACall() and
109122
result.getArgument(0) = getAPrivateFolderPath(description)
110123
}
111124

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
var express = require('express');
3+
4+
var app = express();
5+
6+
app.use('/node_modules', express.static(path.resolve(__dirname, '../node_modules')));
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
var express = require('express');
3+
4+
var app = express();
5+
6+
app.use("jquery", express.static('./node_modules/jquery/dist'));
7+
app.use("bootstrap", express.static('./node_modules/bootstrap/dist'));
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>
7+
Sensitive information included in a build artifact can allow an attacker to access
8+
the sensitive information if the artifact is published.
9+
</p>
10+
</overview>
11+
12+
<recommendation>
13+
<p>
14+
Only store information that is meant to be publicly available in a build artifact.
15+
</p>
16+
</recommendation>
17+
18+
<example>
19+
<p>
20+
The following example creates a <code>webpack</code> configuration that inserts all environment
21+
variables from the host into the build artifact:
22+
</p>
23+
<sample src="examples/build-leak.js"/>
24+
<p>
25+
The environment variables might include API keys or other sensitive information, and the build-system
26+
should instead insert only the environment variables that are supposed to be public.
27+
</p>
28+
<p>
29+
The issue has been fixed below, where only the <code>DEBUG</code> environment variable is inserted into the artifact.
30+
</p>
31+
<sample src="examples/build-leak-fixed.js"/>
32+
</example>
33+
<references>
34+
<li>webpack: <a href="https://webpack.js.org/plugins/define-plugin/">DefinePlugin API</a>.</li>
35+
</references>
36+
</qhelp>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* @name Storage of sensitive information in build artifact
3+
* @description Including sensitive information in a build artifact can
4+
* expose it to an attacker.
5+
* @kind path-problem
6+
* @problem.severity error
7+
* @precision high
8+
* @id js/build-artifact-leak
9+
* @tags security
10+
* external/cwe/cwe-312
11+
* external/cwe/cwe-315
12+
* external/cwe/cwe-359
13+
*/
14+
15+
import javascript
16+
import semmle.javascript.security.dataflow.BuildArtifactLeak::BuildArtifactLeak
17+
import DataFlow::PathGraph
18+
19+
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
20+
where cfg.hasFlowPath(source, sink)
21+
select sink.getNode(), source, sink,
22+
"Sensitive data returned by $@ is stored in a build artifact here.", source.getNode(),
23+
source.getNode().(CleartextLogging::Source).describe()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const webpack = require("webpack");
2+
3+
module.exports = [{
4+
plugins: [
5+
new webpack.DefinePlugin({
6+
'process.env': JSON.stringify({ DEBUG: process.env.DEBUG })
7+
})
8+
]
9+
}];
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const webpack = require("webpack");
2+
3+
module.exports = [{
4+
plugins: [
5+
new webpack.DefinePlugin({
6+
"process.env": JSON.stringify(process.env)
7+
})
8+
]
9+
}];

0 commit comments

Comments
 (0)