This commit is contained in:
amammad
2023-12-10 20:27:21 +01:00
parent 4ef1fe49e3
commit 18d0b28024
7 changed files with 171 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Assigning Value to environment variables from user-controllable data is not safe.
</p>
</overview>
<recommendation>
<p>
Restrict this operation only to privileged users or only for some not important environment variables.
</p>
</recommendation>
<example>
<p>
The following example allows unauthorized users to assign a value to a critical environment variable.
</p>
<sample src="examples/Bad.js" />
</example>
<references>
<a href="https://huntr.com/bounties/00ec6847-125b-43e9-9658-d3cace1751d6/">Admin account TakeOver in mintplex-labs/anything-llm</a>
</references>
</qhelp>

View File

@@ -0,0 +1,31 @@
/**
* @name User controlled environment injection
* @description full control on creating environment variables from user controlled data is not secure
* @kind path-problem
* @id js/envinjection
* @problem.severity error
* @security-severity 7.5
* @precision medium
* @tags security
* external/cwe/cwe-089
*/
import javascript
import DataFlow::PathGraph
/** A taint tracking configuration for unsafe environment injection. */
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "envInjection" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
sink = API::moduleImport("process").getMember("env").getAMember().asSink()
}
}
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "this environment variable assignment is $@.",
source.getNode(), "user controllable"

View File

@@ -0,0 +1,64 @@
/**
* @name User controlled environment injection
* @description full control on creating environment variables from user controlled data is not secure
* @kind path-problem
* @id js/envinjection
* @problem.severity error
* @security-severity 7.5
* @precision medium
* @tags security
* external/cwe/cwe-089
*/
import javascript
import DataFlow::PathGraph
/** A taint tracking configuration for unsafe environment injection. */
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "envInjection" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) {
NodeJSLib::process()
.getAPropertyRead("env")
.asExpr()
.getParent()
.(IndexExpr)
.getAChildExpr()
.(VarRef) = sink.asExpr()
or
sink = API::moduleImport("process").getMember("env").getAMember().asSink()
}
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(DataFlow::InvokeNode ikn |
ikn = DataFlow::globalVarRef("Object").getAMemberInvocation("keys")
|
pred = ikn.getArgument(0) and
(
succ = ikn.getAChainedMethodCall(["filter", "map"]) or
succ = ikn or
succ = ikn.getAChainedMethodCall("forEach").getABoundCallbackParameter(0, 0)
)
)
}
}
from
Configuration cfg, Configuration cfg2, DataFlow::PathNode source, DataFlow::PathNode sink,
DataFlow::PathNode sink2
where
cfg.hasFlowPath(source, sink) and
sink.getNode() = API::moduleImport("process").getMember("env").getAMember().asSink() and
cfg2.hasFlowPath(source, sink2) and
sink.getNode().asExpr() =
NodeJSLib::process()
.getAPropertyRead("env")
.asExpr()
.getParent()
.(IndexExpr)
.getAChildExpr()
.(VarRef)
select sink.getNode(), source, sink, "this environment variable assignment is $@.",
source.getNode(), "user controllable"

View File

@@ -0,0 +1,8 @@
const http = require('node:http');
http.createServer((req, res) => {
const { EnvValue } = req.body;
process.env["A_Critical_Env"] = EnvValue; // NOT OK
res.end('env has been injected!');
});

View File

@@ -0,0 +1,22 @@
nodes
| test.js:4:9:4:20 | { EnvValue } |
| test.js:4:9:4:31 | EnvValue |
| test.js:4:11:4:18 | EnvValue |
| test.js:4:24:4:31 | req.body |
| test.js:4:24:4:31 | req.body |
| test.js:5:35:5:42 | EnvValue |
| test.js:5:35:5:42 | EnvValue |
| test.js:6:23:6:30 | EnvValue |
| test.js:6:23:6:30 | EnvValue |
edges
| test.js:4:9:4:20 | { EnvValue } | test.js:4:11:4:18 | EnvValue |
| test.js:4:9:4:31 | EnvValue | test.js:5:35:5:42 | EnvValue |
| test.js:4:9:4:31 | EnvValue | test.js:5:35:5:42 | EnvValue |
| test.js:4:9:4:31 | EnvValue | test.js:6:23:6:30 | EnvValue |
| test.js:4:9:4:31 | EnvValue | test.js:6:23:6:30 | EnvValue |
| test.js:4:11:4:18 | EnvValue | test.js:4:9:4:31 | EnvValue |
| test.js:4:24:4:31 | req.body | test.js:4:9:4:20 | { EnvValue } |
| test.js:4:24:4:31 | req.body | test.js:4:9:4:20 | { EnvValue } |
#select
| test.js:5:35:5:42 | EnvValue | test.js:4:24:4:31 | req.body | test.js:5:35:5:42 | EnvValue | this environment variable assignment is $@. | test.js:4:24:4:31 | req.body | user controllable |
| test.js:6:23:6:30 | EnvValue | test.js:4:24:4:31 | req.body | test.js:6:23:6:30 | EnvValue | this environment variable assignment is $@. | test.js:4:24:4:31 | req.body | user controllable |

View File

@@ -0,0 +1 @@
experimental/Security/CWE-099/EnvInjection.ql

View File

@@ -0,0 +1,9 @@
const http = require('node:http');
http.createServer((req, res) => {
const { EnvValue } = req.body;
process.env["A_Critical_Env"] = EnvValue; // NOT OK
process.env[AKey] = EnvValue; // NOT OK
res.end('env has been injected!');
});