Skip to content

Commit e4699f7

Browse files
committed
Optimize the query
1 parent d664aa6 commit e4699f7

File tree

5 files changed

+99
-92
lines changed

5 files changed

+99
-92
lines changed

java/ql/src/experimental/Security/CWE/CWE-094/RhinoInjection.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import org.mozilla.javascript.ClassShutter;
2+
import org.mozilla.javascript.Context;
3+
import org.mozilla.javascript.Scriptable;
4+
15
public class RhinoInjection extends HttpServlet {
26

37
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
@@ -20,10 +24,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
2024
Scriptable scope = ctx.initStandardObjects();
2125
ctx.setClassShutter(new ClassShutter() {
2226
public boolean visibleToScripts(String className) {
23-
if(className.startsWith("com.example.")) {
24-
return true;
25-
}
26-
return false;
27+
return className.startsWith("com.example.");
2728
}
2829
});
2930
}

java/ql/src/experimental/Security/CWE/CWE-094/ScriptInjection.ql

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* @name Injection in Java Script Engine
3-
* @description Evaluation of a user-controlled malicious JavaScript or Java expression in
4-
* Java Script Engine may lead to remote code execution.
3+
* @description Evaluation of user-controlled data using the Java Script Engine may
4+
* lead to remote code execution.
55
* @kind path-problem
66
* @problem.severity error
77
* @precision high
@@ -78,43 +78,37 @@ predicate scriptEngine(MethodAccess ma, Expr sink) {
7878
}
7979

8080
/**
81-
* Holds if a Rhino expression evaluation method has the code injection vulnerability.
81+
* Holds if a Rhino expression evaluation method is vulnerable to code injection.
8282
*/
8383
predicate evaluateRhinoExpression(MethodAccess ma, Expr sink) {
8484
exists(RhinoEvaluateExpressionMethod m | m = ma.getMethod() |
8585
(
86-
sink = ma.getArgument(1) and // The second argument is the JavaScript or Java input
87-
not ma.getMethod().getName() = "compileReader"
88-
or
89-
sink = ma.getArgument(0) and // The first argument is the input reader
90-
ma.getMethod().getName() = "compileReader"
86+
if ma.getMethod().getName() = "compileReader"
87+
then sink = ma.getArgument(0) // The first argument is the input reader
88+
else sink = ma.getArgument(1) // The second argument is the JavaScript or Java input
9189
) and
9290
not exists(MethodAccess ca |
93-
(
94-
ca.getMethod().hasName("initSafeStandardObjects") // safe mode
95-
or
96-
ca.getMethod().hasName("setClassShutter") // `ClassShutter` constraint is enforced
97-
) and
91+
ca.getMethod().hasName(["initSafeStandardObjects", "setClassShutter"]) and // safe mode or `ClassShutter` constraint is enforced
9892
ma.getQualifier() = ca.getQualifier().(VarAccess).getVariable().getAnAccess()
9993
)
10094
)
10195
}
10296

10397
/**
104-
* Holds if a Rhino expression compilation method has the code injection vulnerability.
98+
* Holds if a Rhino expression compilation method is vulnerable to code injection.
10599
*/
106100
predicate compileScript(MethodAccess ma, Expr sink) {
107101
exists(RhinoCompileClassMethod m | m = ma.getMethod() | sink = ma.getArgument(0))
108102
}
109103

110104
/**
111-
* Holds if a Rhino class loading method has the code injection vulnerability.
105+
* Holds if a Rhino class loading method is vulnerable to code injection.
112106
*/
113107
predicate defineClass(MethodAccess ma, Expr sink) {
114108
exists(RhinoDefineClassMethod m | m = ma.getMethod() | sink = ma.getArgument(1))
115109
}
116110

117-
/** A sink of script injection. */
111+
/** A script injection sink. */
118112
class ScriptInjectionSink extends DataFlow::ExprNode {
119113
ScriptInjectionSink() {
120114
scriptEngine(_, this.getExpr()) or
@@ -123,6 +117,7 @@ class ScriptInjectionSink extends DataFlow::ExprNode {
123117
defineClass(_, this.getExpr())
124118
}
125119

120+
/** An access to the method associated with this sink. */
126121
MethodAccess getMethodAccess() {
127122
scriptEngine(result, this.getExpr()) or
128123
evaluateRhinoExpression(result, this.getExpr()) or
@@ -134,11 +129,7 @@ class ScriptInjectionSink extends DataFlow::ExprNode {
134129
class ScriptInjectionConfiguration extends TaintTracking::Configuration {
135130
ScriptInjectionConfiguration() { this = "ScriptInjectionConfiguration" }
136131

137-
override predicate isSource(DataFlow::Node source) {
138-
source instanceof RemoteFlowSource
139-
or
140-
source instanceof LocalUserInput
141-
}
132+
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
142133

143134
override predicate isSink(DataFlow::Node sink) { sink instanceof ScriptInjectionSink }
144135
}

java/ql/test/experimental/query-tests/security/CWE-094/RhinoServlet.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,7 @@ protected void doPut(HttpServletRequest request, HttpServletResponse response) t
6363
Scriptable scope = ctx.initStandardObjects();
6464
ctx.setClassShutter(new ClassShutter() {
6565
public boolean visibleToScripts(String className) {
66-
if(className.startsWith("com.example.")) {
67-
return true;
68-
}
69-
return false;
66+
return className.startsWith("com.example.");
7067
}
7168
});
7269

java/ql/test/experimental/query-tests/security/CWE-094/ScriptEngineTest.java

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
1+
import javax.script.AbstractScriptEngine;
2+
import javax.script.Compilable;
3+
import javax.script.CompiledScript;
4+
import javax.script.ScriptEngine;
5+
import javax.script.ScriptEngineManager;
6+
import javax.script.ScriptEngineFactory;
7+
import javax.script.ScriptException;
8+
19
import jdk.nashorn.api.scripting.NashornScriptEngine;
210
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
3-
import javax.script.*;
411

12+
import java.io.IOException;
13+
import javax.servlet.ServletException;
14+
import javax.servlet.http.HttpServlet;
15+
import javax.servlet.http.HttpServletRequest;
16+
import javax.servlet.http.HttpServletResponse;
517

6-
public class ScriptEngineTest {
18+
public class ScriptEngineTest extends HttpServlet {
719

820
public void testWithScriptEngineReference(String input) throws ScriptException {
921
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
@@ -47,16 +59,7 @@ public void testScriptEngineGetProgram(String input) throws ScriptException {
4759
String program = engine.getFactory().getProgram(input);
4860
Object result = engine.eval(program);
4961
}
50-
51-
public static void main(String[] args) throws ScriptException {
52-
new ScriptEngineTest().testWithScriptEngineReference(args[0]);
53-
new ScriptEngineTest().testNashornWithScriptEngineReference(args[0]);
54-
new ScriptEngineTest().testNashornWithNashornScriptEngineReference(args[0]);
55-
new ScriptEngineTest().testCustomScriptEngineReference(args[0]);
56-
new ScriptEngineTest().testScriptEngineCompilable(args[0]);
57-
new ScriptEngineTest().testScriptEngineGetProgram(args[0]);
58-
}
59-
62+
6063
private static class MyCustomScriptEngine extends AbstractScriptEngine {
6164
public Object eval(String var1) throws ScriptException { return null; }
6265

@@ -82,4 +85,19 @@ public MyCustomFactory() {
8285
@Override
8386
public String getProgram(final String... statements) { return null; }
8487
}
88+
89+
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
90+
try {
91+
String code = request.getParameter("code");
92+
93+
new ScriptEngineTest().testWithScriptEngineReference(code);
94+
new ScriptEngineTest().testNashornWithScriptEngineReference(code);
95+
new ScriptEngineTest().testNashornWithNashornScriptEngineReference(code);
96+
new ScriptEngineTest().testCustomScriptEngineReference(code);
97+
new ScriptEngineTest().testScriptEngineCompilable(code);
98+
new ScriptEngineTest().testScriptEngineGetProgram(code);
99+
} catch (ScriptException se) {
100+
throw new IOException(se.getMessage());
101+
}
102+
}
85103
}
Lines changed: 51 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,58 @@
11
edges
22
| RhinoServlet.java:28:23:28:50 | getParameter(...) : String | RhinoServlet.java:32:55:32:58 | code |
3-
| RhinoServlet.java:84:23:84:50 | getParameter(...) : String | RhinoServlet.java:86:54:86:57 | code |
4-
| RhinoServlet.java:91:23:91:50 | getParameter(...) : String | RhinoServlet.java:92:74:92:88 | getBytes(...) |
5-
| ScriptEngineTest.java:8:44:8:55 | input : String | ScriptEngineTest.java:12:37:12:41 | input |
6-
| ScriptEngineTest.java:15:51:15:62 | input : String | ScriptEngineTest.java:19:31:19:35 | input |
7-
| ScriptEngineTest.java:23:58:23:69 | input : String | ScriptEngineTest.java:27:31:27:35 | input |
8-
| ScriptEngineTest.java:30:46:30:57 | input : String | ScriptEngineTest.java:34:31:34:35 | input |
9-
| ScriptEngineTest.java:37:41:37:52 | input : String | ScriptEngineTest.java:40:42:40:46 | input |
10-
| ScriptEngineTest.java:44:41:44:52 | input : String | ScriptEngineTest.java:47:51:47:55 | input |
11-
| ScriptEngineTest.java:51:26:51:38 | args : String[] | ScriptEngineTest.java:52:56:52:62 | ...[...] : String |
12-
| ScriptEngineTest.java:51:26:51:38 | args : String[] | ScriptEngineTest.java:53:63:53:69 | ...[...] : String |
13-
| ScriptEngineTest.java:51:26:51:38 | args : String[] | ScriptEngineTest.java:54:70:54:76 | ...[...] : String |
14-
| ScriptEngineTest.java:51:26:51:38 | args : String[] | ScriptEngineTest.java:55:58:55:64 | ...[...] : String |
15-
| ScriptEngineTest.java:51:26:51:38 | args : String[] | ScriptEngineTest.java:56:53:56:59 | ...[...] : String |
16-
| ScriptEngineTest.java:51:26:51:38 | args : String[] | ScriptEngineTest.java:57:53:57:59 | ...[...] : String |
17-
| ScriptEngineTest.java:52:56:52:62 | ...[...] : String | ScriptEngineTest.java:8:44:8:55 | input : String |
18-
| ScriptEngineTest.java:53:63:53:69 | ...[...] : String | ScriptEngineTest.java:15:51:15:62 | input : String |
19-
| ScriptEngineTest.java:54:70:54:76 | ...[...] : String | ScriptEngineTest.java:23:58:23:69 | input : String |
20-
| ScriptEngineTest.java:55:58:55:64 | ...[...] : String | ScriptEngineTest.java:30:46:30:57 | input : String |
21-
| ScriptEngineTest.java:56:53:56:59 | ...[...] : String | ScriptEngineTest.java:37:41:37:52 | input : String |
22-
| ScriptEngineTest.java:57:53:57:59 | ...[...] : String | ScriptEngineTest.java:44:41:44:52 | input : String |
3+
| RhinoServlet.java:81:23:81:50 | getParameter(...) : String | RhinoServlet.java:83:54:83:57 | code |
4+
| RhinoServlet.java:88:23:88:50 | getParameter(...) : String | RhinoServlet.java:89:74:89:88 | getBytes(...) |
5+
| ScriptEngineTest.java:20:44:20:55 | input : String | ScriptEngineTest.java:24:37:24:41 | input |
6+
| ScriptEngineTest.java:27:51:27:62 | input : String | ScriptEngineTest.java:31:31:31:35 | input |
7+
| ScriptEngineTest.java:35:58:35:69 | input : String | ScriptEngineTest.java:39:31:39:35 | input |
8+
| ScriptEngineTest.java:42:46:42:57 | input : String | ScriptEngineTest.java:46:31:46:35 | input |
9+
| ScriptEngineTest.java:49:41:49:52 | input : String | ScriptEngineTest.java:52:42:52:46 | input |
10+
| ScriptEngineTest.java:56:41:56:52 | input : String | ScriptEngineTest.java:59:51:59:55 | input |
11+
| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:93:57:93:60 | code : String |
12+
| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:94:64:94:67 | code : String |
13+
| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:95:71:95:74 | code : String |
14+
| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:96:59:96:62 | code : String |
15+
| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:97:54:97:57 | code : String |
16+
| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:98:54:98:57 | code : String |
17+
| ScriptEngineTest.java:93:57:93:60 | code : String | ScriptEngineTest.java:20:44:20:55 | input : String |
18+
| ScriptEngineTest.java:94:64:94:67 | code : String | ScriptEngineTest.java:27:51:27:62 | input : String |
19+
| ScriptEngineTest.java:95:71:95:74 | code : String | ScriptEngineTest.java:35:58:35:69 | input : String |
20+
| ScriptEngineTest.java:96:59:96:62 | code : String | ScriptEngineTest.java:42:46:42:57 | input : String |
21+
| ScriptEngineTest.java:97:54:97:57 | code : String | ScriptEngineTest.java:49:41:49:52 | input : String |
22+
| ScriptEngineTest.java:98:54:98:57 | code : String | ScriptEngineTest.java:56:41:56:52 | input : String |
2323
nodes
2424
| RhinoServlet.java:28:23:28:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
2525
| RhinoServlet.java:32:55:32:58 | code | semmle.label | code |
26-
| RhinoServlet.java:84:23:84:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
27-
| RhinoServlet.java:86:54:86:57 | code | semmle.label | code |
28-
| RhinoServlet.java:91:23:91:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
29-
| RhinoServlet.java:92:74:92:88 | getBytes(...) | semmle.label | getBytes(...) |
30-
| ScriptEngineTest.java:8:44:8:55 | input : String | semmle.label | input : String |
31-
| ScriptEngineTest.java:12:37:12:41 | input | semmle.label | input |
32-
| ScriptEngineTest.java:15:51:15:62 | input : String | semmle.label | input : String |
33-
| ScriptEngineTest.java:19:31:19:35 | input | semmle.label | input |
34-
| ScriptEngineTest.java:23:58:23:69 | input : String | semmle.label | input : String |
35-
| ScriptEngineTest.java:27:31:27:35 | input | semmle.label | input |
36-
| ScriptEngineTest.java:30:46:30:57 | input : String | semmle.label | input : String |
37-
| ScriptEngineTest.java:34:31:34:35 | input | semmle.label | input |
38-
| ScriptEngineTest.java:37:41:37:52 | input : String | semmle.label | input : String |
39-
| ScriptEngineTest.java:40:42:40:46 | input | semmle.label | input |
40-
| ScriptEngineTest.java:44:41:44:52 | input : String | semmle.label | input : String |
41-
| ScriptEngineTest.java:47:51:47:55 | input | semmle.label | input |
42-
| ScriptEngineTest.java:51:26:51:38 | args : String[] | semmle.label | args : String[] |
43-
| ScriptEngineTest.java:52:56:52:62 | ...[...] : String | semmle.label | ...[...] : String |
44-
| ScriptEngineTest.java:53:63:53:69 | ...[...] : String | semmle.label | ...[...] : String |
45-
| ScriptEngineTest.java:54:70:54:76 | ...[...] : String | semmle.label | ...[...] : String |
46-
| ScriptEngineTest.java:55:58:55:64 | ...[...] : String | semmle.label | ...[...] : String |
47-
| ScriptEngineTest.java:56:53:56:59 | ...[...] : String | semmle.label | ...[...] : String |
48-
| ScriptEngineTest.java:57:53:57:59 | ...[...] : String | semmle.label | ...[...] : String |
26+
| RhinoServlet.java:81:23:81:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
27+
| RhinoServlet.java:83:54:83:57 | code | semmle.label | code |
28+
| RhinoServlet.java:88:23:88:50 | getParameter(...) : String | semmle.label | getParameter(...) : String |
29+
| RhinoServlet.java:89:74:89:88 | getBytes(...) | semmle.label | getBytes(...) |
30+
| ScriptEngineTest.java:20:44:20:55 | input : String | semmle.label | input : String |
31+
| ScriptEngineTest.java:24:37:24:41 | input | semmle.label | input |
32+
| ScriptEngineTest.java:27:51:27:62 | input : String | semmle.label | input : String |
33+
| ScriptEngineTest.java:31:31:31:35 | input | semmle.label | input |
34+
| ScriptEngineTest.java:35:58:35:69 | input : String | semmle.label | input : String |
35+
| ScriptEngineTest.java:39:31:39:35 | input | semmle.label | input |
36+
| ScriptEngineTest.java:42:46:42:57 | input : String | semmle.label | input : String |
37+
| ScriptEngineTest.java:46:31:46:35 | input | semmle.label | input |
38+
| ScriptEngineTest.java:49:41:49:52 | input : String | semmle.label | input : String |
39+
| ScriptEngineTest.java:52:42:52:46 | input | semmle.label | input |
40+
| ScriptEngineTest.java:56:41:56:52 | input : String | semmle.label | input : String |
41+
| ScriptEngineTest.java:59:51:59:55 | input | semmle.label | input |
42+
| ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
43+
| ScriptEngineTest.java:93:57:93:60 | code : String | semmle.label | code : String |
44+
| ScriptEngineTest.java:94:64:94:67 | code : String | semmle.label | code : String |
45+
| ScriptEngineTest.java:95:71:95:74 | code : String | semmle.label | code : String |
46+
| ScriptEngineTest.java:96:59:96:62 | code : String | semmle.label | code : String |
47+
| ScriptEngineTest.java:97:54:97:57 | code : String | semmle.label | code : String |
48+
| ScriptEngineTest.java:98:54:98:57 | code : String | semmle.label | code : String |
4949
#select
5050
| RhinoServlet.java:32:29:32:78 | evaluateString(...) | RhinoServlet.java:28:23:28:50 | getParameter(...) : String | RhinoServlet.java:32:55:32:58 | code | Java Script Engine evaluate $@. | RhinoServlet.java:28:23:28:50 | getParameter(...) | user input |
51-
| RhinoServlet.java:86:25:86:97 | compileToClassFiles(...) | RhinoServlet.java:84:23:84:50 | getParameter(...) : String | RhinoServlet.java:86:54:86:57 | code | Java Script Engine evaluate $@. | RhinoServlet.java:84:23:84:50 | getParameter(...) | user input |
52-
| RhinoServlet.java:92:23:92:89 | defineClass(...) | RhinoServlet.java:91:23:91:50 | getParameter(...) : String | RhinoServlet.java:92:74:92:88 | getBytes(...) | Java Script Engine evaluate $@. | RhinoServlet.java:91:23:91:50 | getParameter(...) | user input |
53-
| ScriptEngineTest.java:12:19:12:42 | eval(...) | ScriptEngineTest.java:51:26:51:38 | args : String[] | ScriptEngineTest.java:12:37:12:41 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:51:26:51:38 | args | user input |
54-
| ScriptEngineTest.java:19:19:19:36 | eval(...) | ScriptEngineTest.java:51:26:51:38 | args : String[] | ScriptEngineTest.java:19:31:19:35 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:51:26:51:38 | args | user input |
55-
| ScriptEngineTest.java:27:19:27:36 | eval(...) | ScriptEngineTest.java:51:26:51:38 | args : String[] | ScriptEngineTest.java:27:31:27:35 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:51:26:51:38 | args | user input |
56-
| ScriptEngineTest.java:34:19:34:36 | eval(...) | ScriptEngineTest.java:51:26:51:38 | args : String[] | ScriptEngineTest.java:34:31:34:35 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:51:26:51:38 | args | user input |
57-
| ScriptEngineTest.java:40:27:40:47 | compile(...) | ScriptEngineTest.java:51:26:51:38 | args : String[] | ScriptEngineTest.java:40:42:40:46 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:51:26:51:38 | args | user input |
58-
| ScriptEngineTest.java:47:20:47:56 | getProgram(...) | ScriptEngineTest.java:51:26:51:38 | args : String[] | ScriptEngineTest.java:47:51:47:55 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:51:26:51:38 | args | user input |
51+
| RhinoServlet.java:83:25:83:97 | compileToClassFiles(...) | RhinoServlet.java:81:23:81:50 | getParameter(...) : String | RhinoServlet.java:83:54:83:57 | code | Java Script Engine evaluate $@. | RhinoServlet.java:81:23:81:50 | getParameter(...) | user input |
52+
| RhinoServlet.java:89:23:89:89 | defineClass(...) | RhinoServlet.java:88:23:88:50 | getParameter(...) : String | RhinoServlet.java:89:74:89:88 | getBytes(...) | Java Script Engine evaluate $@. | RhinoServlet.java:88:23:88:50 | getParameter(...) | user input |
53+
| ScriptEngineTest.java:24:19:24:42 | eval(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:24:37:24:41 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
54+
| ScriptEngineTest.java:31:19:31:36 | eval(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:31:31:31:35 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
55+
| ScriptEngineTest.java:39:19:39:36 | eval(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:39:31:39:35 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
56+
| ScriptEngineTest.java:46:19:46:36 | eval(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:46:31:46:35 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
57+
| ScriptEngineTest.java:52:27:52:47 | compile(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:52:42:52:46 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |
58+
| ScriptEngineTest.java:59:20:59:56 | getProgram(...) | ScriptEngineTest.java:91:18:91:45 | getParameter(...) : String | ScriptEngineTest.java:59:51:59:55 | input | Java Script Engine evaluate $@. | ScriptEngineTest.java:91:18:91:45 | getParameter(...) | user input |

0 commit comments

Comments
 (0)