Skip to content

Commit 5e0a78c

Browse files
committed
make predicate for env key and value nodes, use propertyRead/Write instead of API nodes to find env key and value assignments, fix a bug thanks to @erik-krogh
1 parent 2b929c4 commit 5e0a78c

File tree

2 files changed

+37
-23
lines changed

2 files changed

+37
-23
lines changed

javascript/ql/src/experimental/Security/CWE-099/EnvValueAndKeyInjection.ql

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,8 @@ class Configuration extends TaintTracking::Configuration {
2020
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
2121

2222
override predicate isSink(DataFlow::Node sink) {
23-
NodeJSLib::process()
24-
.getAPropertyRead("env")
25-
.asExpr()
26-
.getParent()
27-
.(IndexExpr)
28-
.getAChildExpr()
29-
.(VarRef) = sink.asExpr()
30-
or
31-
sink = API::moduleImport("process").getMember("env").getAMember().asSink()
23+
sink = keyOfEnv() or
24+
sink = valueOfEnv()
3225
}
3326

3427
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
@@ -45,20 +38,32 @@ class Configuration extends TaintTracking::Configuration {
4538
}
4639
}
4740

41+
DataFlow::Node keyOfEnv() {
42+
result =
43+
NodeJSLib::process().getAPropertyRead("env").getAPropertyWrite().getPropertyNameExpr().flow()
44+
}
45+
46+
DataFlow::Node valueOfEnv() {
47+
result = API::moduleImport("process").getMember("env").getAMember().asSink()
48+
}
49+
50+
private predicate readToProcessEnv(DataFlow::Node envKey, DataFlow::Node envValue) {
51+
exists(DataFlow::PropWrite env |
52+
env = NodeJSLib::process().getAPropertyRead("env").getAPropertyWrite()
53+
|
54+
envKey = env.getPropertyNameExpr().flow() and
55+
envValue = env.getRhs()
56+
)
57+
}
58+
4859
from
49-
Configuration cfg, Configuration cfg2, DataFlow::PathNode source, DataFlow::PathNode sink1,
50-
DataFlow::PathNode sink2
60+
Configuration cfgForValue, Configuration cfgForKey, DataFlow::PathNode source,
61+
DataFlow::PathNode envKey, DataFlow::PathNode envValue
5162
where
52-
cfg.hasFlowPath(source, sink1) and
53-
sink1.getNode() = API::moduleImport("process").getMember("env").getAMember().asSink() and
54-
cfg2.hasFlowPath(source, sink2) and
55-
sink2.getNode().asExpr() =
56-
NodeJSLib::process()
57-
.getAPropertyRead("env")
58-
.asExpr()
59-
.getParent()
60-
.(IndexExpr)
61-
.getAChildExpr()
62-
.(VarRef)
63-
select sink1.getNode(), source, sink1, "arbitrary environment variable assignment from this $@.",
63+
cfgForValue.hasFlowPath(source, envKey) and
64+
envKey.getNode() = keyOfEnv() and
65+
cfgForKey.hasFlowPath(source, envValue) and
66+
envValue.getNode() = valueOfEnv() and
67+
readToProcessEnv(envKey.getNode(), envValue.getNode())
68+
select envKey.getNode(), source, envKey, "arbitrary environment variable assignment from this $@.",
6469
source.getNode(), "user controllable source"

javascript/ql/test/experimental/Security/CWE-099/EnvValueAndKeyInjection/test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,14 @@ http.createServer((req, res) => {
77
process.env[EnvKey] = EnvValue; // NOT OK
88
process.env.EnvKey = EnvValue; // NOT OK
99

10+
res.end('env has been injected!');
11+
});
12+
13+
http.createServer((req, res) => {
14+
const { EnvValue, EnvKey } = req.body;
15+
16+
process.env[EnvKey] = "constant" // OK
17+
process.env.constant = EnvValue // OK
18+
1019
res.end('env has been injected!');
1120
});

0 commit comments

Comments
 (0)