Skip to content

Commit 9fc75f1

Browse files
authored
Merge pull request github#2850 from SpaceWhite/CWE-094
ScriptEngine java code injection
2 parents 2a2484e + 822bfcd commit 9fc75f1

File tree

3 files changed

+80
-0
lines changed

3 files changed

+80
-0
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Bad: ScriptEngine allows arbitrary code injection
2+
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
3+
ScriptEngine scriptEngine = scriptEngineManager.getEngineByExtension("js");
4+
Object result = scriptEngine.eval(code);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>The ScriptEngine API has been available since the release of Java 6.
8+
It allows applications to interact with scripts written in languages such as JavaScript.</p>
9+
</overview>
10+
11+
<recommendation>
12+
<p>Use "Cloudbees Rhino Sandbox" or sandboxing with SecurityManager or use <a href="https://www.graalvm.org/">graalvm</a> instead.</p>
13+
</recommendation>
14+
15+
<example>
16+
<p>The following code could execute random JavaScript code</p>
17+
<sample src="ScriptEngine.java" />
18+
</example>
19+
20+
<references>
21+
<li>
22+
CERT coding standard: <a href="https://wiki.sei.cmu.edu/confluence/display/java/IDS52-J.+Prevent+code+injection">ScriptEngine code injection</a>
23+
</li>
24+
</references>
25+
</qhelp>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* @name ScriptEngine evaluation
3+
* @description Malicious Javascript code could cause arbitrary command execution at the OS level
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @precision high
7+
* @id java/unsafe-eval
8+
* @tags security
9+
* external/cwe/cwe-094
10+
*/
11+
12+
import java
13+
import semmle.code.java.dataflow.FlowSources
14+
import DataFlow::PathGraph
15+
16+
class ScriptEngineMethod extends Method {
17+
ScriptEngineMethod() {
18+
this.getDeclaringType().hasQualifiedName("javax.script", "ScriptEngine") and
19+
this.hasName("eval")
20+
}
21+
}
22+
23+
predicate scriptEngine(MethodAccess ma, Expr sink) {
24+
exists(Method m | m = ma.getMethod() |
25+
m instanceof ScriptEngineMethod and
26+
sink = ma.getArgument(0)
27+
)
28+
}
29+
30+
class ScriptEngineSink extends DataFlow::ExprNode {
31+
ScriptEngineSink() { scriptEngine(_, this.getExpr()) }
32+
33+
MethodAccess getMethodAccess() { scriptEngine(result, this.getExpr()) }
34+
}
35+
36+
class ScriptEngineConfiguration extends TaintTracking::Configuration {
37+
ScriptEngineConfiguration() { this = "ScriptEngineConfiguration" }
38+
39+
override predicate isSource(DataFlow::Node source) {
40+
source instanceof RemoteFlowSource
41+
or
42+
source instanceof LocalUserInput
43+
}
44+
45+
override predicate isSink(DataFlow::Node sink) { sink instanceof ScriptEngineSink }
46+
}
47+
48+
from DataFlow::PathNode source, DataFlow::PathNode sink, ScriptEngineConfiguration conf
49+
where conf.hasFlowPath(source, sink)
50+
select sink.getNode().(ScriptEngineSink).getMethodAccess(), source, sink, "ScriptEngine eval $@.",
51+
source.getNode(), "user input"

0 commit comments

Comments
 (0)