Skip to content

Commit 4bc9096

Browse files
committed
Ruby: Add case string comparison barrier guard
This recognises barriers of the form STRINGS = ["foo", "bar"] case foo when "some string literal" foo when *["other", "strings"] foo when *STRINGS foo end where the reads of `foo` inside each `when` are guarded by the comparison of `foo` with the string literals. We don't yet recognise this construct: case foo when "foo", "bar" foo end This is due to a limitation in the shared barrier guard logic.
1 parent cfbaf5e commit 4bc9096

File tree

9 files changed

+233
-37
lines changed

9 files changed

+233
-37
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* String literals and arrays of string literals in case expression patterns are now recognised as barrier guards.

ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ module ExprNodes {
234234
override predicate relevantChild(AstNode n) { none() }
235235
}
236236

237-
/** A control-flow node that wraps an `ArrayLiteral` AST expression. */
237+
/** A control-flow node that wraps a `Literal` AST expression. */
238238
class LiteralCfgNode extends ExprCfgNode {
239239
override string getAPrimaryQlClass() { result = "LiteralCfgNode" }
240240

@@ -866,6 +866,17 @@ module ExprNodes {
866866
final override RelationalOperation getExpr() { result = super.getExpr() }
867867
}
868868

869+
/** A control-flow node that wraps a `SplatExpr` AST expression. */
870+
class SplatExprCfgNode extends ExprCfgNode {
871+
override string getAPrimaryQlClass() { result = "SplatExprCfgNode" }
872+
873+
SplatExprCfgNode() { e instanceof SplatExpr }
874+
875+
final override SplatExpr getExpr() { result = super.getExpr() }
876+
877+
final ExprCfgNode getOperand() { result.getExpr() = e.(SplatExpr).getOperand() }
878+
}
879+
869880
/** A control-flow node that wraps an `ElementReference` AST expression. */
870881
class ElementReferenceCfgNode extends MethodCallCfgNode {
871882
override string getAPrimaryQlClass() { result = "ElementReferenceCfgNode" }

ruby/ql/lib/codeql/ruby/dataflow/BarrierGuards.qll

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,23 @@ private import codeql.ruby.dataflow.SSA
88
private import codeql.ruby.ast.internal.Constant
99
private import codeql.ruby.InclusionTests
1010

11-
private predicate stringConstCompare(CfgNodes::ExprCfgNode g, CfgNode e, boolean branch) {
11+
private predicate stringConstCompare(CfgNodes::AstCfgNode guard, CfgNode testedNode, boolean branch) {
1212
exists(CfgNodes::ExprNodes::ComparisonOperationCfgNode c |
13-
c = g and
13+
c = guard and
1414
exists(CfgNodes::ExprNodes::StringLiteralCfgNode strLitNode |
1515
c.getExpr() instanceof EqExpr and branch = true
1616
or
1717
c.getExpr() instanceof CaseEqExpr and branch = true
1818
or
1919
c.getExpr() instanceof NEExpr and branch = false
2020
|
21-
c.getLeftOperand() = strLitNode and c.getRightOperand() = e
21+
c.getLeftOperand() = strLitNode and c.getRightOperand() = testedNode
2222
or
23-
c.getLeftOperand() = e and c.getRightOperand() = strLitNode
23+
c.getLeftOperand() = testedNode and c.getRightOperand() = strLitNode
2424
)
2525
)
26+
or
27+
stringConstCaseCompare(guard, testedNode, branch)
2628
}
2729

2830
/**
@@ -72,10 +74,12 @@ deprecated class StringConstCompare extends DataFlow::BarrierGuard,
7274
}
7375
}
7476

75-
private predicate stringConstArrayInclusionCall(CfgNodes::ExprCfgNode g, CfgNode e, boolean branch) {
77+
private predicate stringConstArrayInclusionCall(
78+
CfgNodes::AstCfgNode guard, CfgNode testedNode, boolean branch
79+
) {
7680
exists(InclusionTest t |
77-
t.asExpr() = g and
78-
e = t.getContainedNode().asExpr() and
81+
t.asExpr() = guard and
82+
testedNode = t.getContainedNode().asExpr() and
7983
branch = t.getPolarity()
8084
|
8185
exists(ExprNodes::ArrayLiteralCfgNode arr |
@@ -132,3 +136,57 @@ deprecated class StringConstArrayInclusionCall extends DataFlow::BarrierGuard,
132136

133137
override predicate checks(CfgNode expr, boolean branch) { expr = checkedNode and branch = true }
134138
}
139+
140+
/**
141+
* A validation of a value by comparing with a constant string via a `case`
142+
* expression. For example:
143+
*
144+
* ```rb
145+
* name = params[:user_name]
146+
* case name
147+
* when "alice"
148+
* User.find_by("username = #{name}")
149+
* when *["bob", "charlie"]
150+
* User.find_by("username = #{name}")
151+
* when "dave", "eve" # this is not yet recognised as a barrier guard
152+
* User.find_by("username = #{name}")
153+
* end
154+
* ```
155+
*/
156+
private predicate stringConstCaseCompare(
157+
CfgNodes::AstCfgNode guard, CfgNode testedNode, boolean branch
158+
) {
159+
branch = true and
160+
exists(CfgNodes::ExprNodes::CaseExprCfgNode case |
161+
case.getValue() = testedNode and
162+
exists(CfgNodes::ExprNodes::WhenClauseCfgNode branchNode |
163+
branchNode = case.getBranch(_) and
164+
guard = branchNode.getPattern(_) and
165+
// For simplicity, consider patterns that contain only string literals or arrays of string literals
166+
forall(ExprCfgNode pattern | pattern = branchNode.getPattern(_) |
167+
// when "foo"
168+
// when "foo", "bar"
169+
pattern instanceof ExprNodes::StringLiteralCfgNode
170+
or
171+
// array literals behave weirdly in the CFG so we need to drop down to the AST level for this bit
172+
// specifically: `SplatExprCfgNode.getOperand()` does not return results for array literals
173+
exists(CfgNodes::ExprNodes::SplatExprCfgNode splat | splat = pattern |
174+
// when *["foo", "bar"]
175+
exists(ArrayLiteral arr |
176+
splat.getExpr().getOperand() = arr and
177+
forall(Expr elem | elem = arr.getAnElement() | elem instanceof StringLiteral)
178+
)
179+
or
180+
// when *some_var
181+
// when *SOME_CONST
182+
exists(ExprNodes::ArrayLiteralCfgNode arr |
183+
isArrayConstant(splat.getOperand(), arr) and
184+
forall(ExprCfgNode elem | elem = arr.getAnArgument() |
185+
elem instanceof ExprNodes::StringLiteralCfgNode
186+
)
187+
)
188+
)
189+
)
190+
)
191+
)
192+
}

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ class ContentSet extends TContentSet {
434434
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
435435
* the argument `x`.
436436
*/
437-
signature predicate guardChecksSig(CfgNodes::ExprCfgNode g, CfgNode e, boolean branch);
437+
signature predicate guardChecksSig(CfgNodes::AstCfgNode g, CfgNode e, boolean branch);
438438

439439
/**
440440
* Provides a set of barrier nodes for a guard that validates an expression.
@@ -444,21 +444,21 @@ signature predicate guardChecksSig(CfgNodes::ExprCfgNode g, CfgNode e, boolean b
444444
*/
445445
module BarrierGuard<guardChecksSig/3 guardChecks> {
446446
pragma[nomagic]
447-
private predicate guardChecksSsaDef(CfgNodes::ExprCfgNode g, boolean branch, Ssa::Definition def) {
447+
private predicate guardChecksSsaDef(CfgNodes::AstCfgNode g, boolean branch, Ssa::Definition def) {
448448
guardChecks(g, def.getARead(), branch)
449449
}
450450

451451
pragma[nomagic]
452452
private predicate guardControlsSsaDef(
453-
CfgNodes::ExprCfgNode g, boolean branch, Ssa::Definition def, Node n
453+
CfgNodes::AstCfgNode g, boolean branch, Ssa::Definition def, Node n
454454
) {
455455
def.getARead() = n.asExpr() and
456456
guardControlsBlock(g, n.asExpr().getBasicBlock(), branch)
457457
}
458458

459459
/** Gets a node that is safely guarded by the given guard check. */
460460
Node getABarrierNode() {
461-
exists(CfgNodes::ExprCfgNode g, boolean branch, Ssa::Definition def |
461+
exists(CfgNodes::AstCfgNode g, boolean branch, Ssa::Definition def |
462462
guardChecksSsaDef(g, branch, def) and
463463
guardControlsSsaDef(g, branch, def, result)
464464
)
@@ -488,8 +488,8 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
488488
}
489489

490490
/** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */
491-
private predicate guardControlsBlock(CfgNodes::ExprCfgNode guard, BasicBlock bb, boolean branch) {
492-
exists(ConditionBlock conditionBlock, SuccessorTypes::BooleanSuccessor s |
491+
private predicate guardControlsBlock(CfgNodes::AstCfgNode guard, BasicBlock bb, boolean branch) {
492+
exists(ConditionBlock conditionBlock, SuccessorTypes::ConditionalSuccessor s |
493493
guard = conditionBlock.getLastNode() and
494494
s.getValue() = branch and
495495
conditionBlock.controls(bb, s)

ruby/ql/lib/codeql/ruby/security/regexp/PolynomialReDoSCustomizations.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ module PolynomialReDoS {
127127
override DataFlow::Node getHighlight() { result = matchNode }
128128
}
129129

130-
private predicate lengthGuard(CfgNodes::ExprCfgNode g, CfgNode node, boolean branch) {
130+
private predicate lengthGuard(CfgNodes::AstCfgNode g, CfgNode node, boolean branch) {
131131
exists(DataFlow::Node input, DataFlow::CallNode length, DataFlow::ExprNode operand |
132132
length.asExpr().getExpr().(Ast::MethodCall).getMethodName() = "length" and
133133
length.getReceiver() = input and

ruby/ql/test/library-tests/dataflow/barrier-guards/barrier-guards.expected

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ newStyleBarrierGuards
2020
| barrier-guards.rb:71:5:71:7 | foo |
2121
| barrier-guards.rb:83:5:83:7 | foo |
2222
| barrier-guards.rb:91:5:91:7 | foo |
23+
| barrier-guards.rb:126:5:126:7 | foo |
24+
| barrier-guards.rb:133:5:133:7 | foo |
25+
| barrier-guards.rb:135:5:135:7 | foo |
26+
| barrier-guards.rb:149:5:149:7 | foo |
27+
| barrier-guards.rb:154:5:154:7 | foo |
28+
| barrier-guards.rb:159:5:159:7 | foo |
29+
| barrier-guards.rb:164:5:164:7 | foo |
2330
controls
2431
| barrier-guards.rb:3:4:3:15 | ... == ... | barrier-guards.rb:4:5:4:7 | foo | true |
2532
| barrier-guards.rb:3:4:3:15 | ... == ... | barrier-guards.rb:6:5:6:7 | foo | false |
@@ -67,3 +74,33 @@ controls
6774
| barrier-guards.rb:118:8:118:8 | call to x | barrier-guards.rb:118:4:118:8 | [true] not ... | false |
6875
| barrier-guards.rb:118:8:118:8 | call to x | barrier-guards.rb:119:5:119:7 | foo | false |
6976
| barrier-guards.rb:118:8:118:8 | call to x | barrier-guards.rb:121:5:121:8 | bars | true |
77+
| barrier-guards.rb:125:6:125:10 | "foo" | barrier-guards.rb:126:5:126:7 | foo | match |
78+
| barrier-guards.rb:125:6:125:10 | "foo" | barrier-guards.rb:128:5:128:7 | foo | no-match |
79+
| barrier-guards.rb:132:6:132:10 | "foo" | barrier-guards.rb:133:5:133:7 | foo | match |
80+
| barrier-guards.rb:132:6:132:10 | "foo" | barrier-guards.rb:134:1:135:7 | when ... | no-match |
81+
| barrier-guards.rb:132:6:132:10 | "foo" | barrier-guards.rb:135:5:135:7 | foo | no-match |
82+
| barrier-guards.rb:134:6:134:10 | "bar" | barrier-guards.rb:135:5:135:7 | foo | match |
83+
| barrier-guards.rb:139:6:139:10 | "foo" | barrier-guards.rb:139:14:139:16 | bar | no-match |
84+
| barrier-guards.rb:139:6:139:10 | "foo" | barrier-guards.rb:141:1:142:7 | when ... | no-match |
85+
| barrier-guards.rb:139:6:139:10 | "foo" | barrier-guards.rb:141:14:141:17 | quux | no-match |
86+
| barrier-guards.rb:139:6:139:10 | "foo" | barrier-guards.rb:142:5:142:7 | foo | no-match |
87+
| barrier-guards.rb:139:6:139:10 | "foo" | barrier-guards.rb:144:5:144:7 | foo | no-match |
88+
| barrier-guards.rb:139:13:139:17 | "bar" | barrier-guards.rb:141:1:142:7 | when ... | no-match |
89+
| barrier-guards.rb:139:13:139:17 | "bar" | barrier-guards.rb:141:14:141:17 | quux | no-match |
90+
| barrier-guards.rb:139:13:139:17 | "bar" | barrier-guards.rb:142:5:142:7 | foo | no-match |
91+
| barrier-guards.rb:139:13:139:17 | "bar" | barrier-guards.rb:144:5:144:7 | foo | no-match |
92+
| barrier-guards.rb:141:6:141:10 | "baz" | barrier-guards.rb:141:14:141:17 | quux | no-match |
93+
| barrier-guards.rb:141:6:141:10 | "baz" | barrier-guards.rb:144:5:144:7 | foo | no-match |
94+
| barrier-guards.rb:141:13:141:18 | "quux" | barrier-guards.rb:144:5:144:7 | foo | no-match |
95+
| barrier-guards.rb:148:6:148:20 | * ... | barrier-guards.rb:149:5:149:7 | foo | match |
96+
| barrier-guards.rb:153:6:153:17 | * ... | barrier-guards.rb:154:5:154:7 | foo | match |
97+
| barrier-guards.rb:158:6:158:9 | * ... | barrier-guards.rb:159:5:159:7 | foo | match |
98+
| barrier-guards.rb:163:6:163:10 | * ... | barrier-guards.rb:164:5:164:7 | foo | match |
99+
| barrier-guards.rb:168:6:168:16 | * ... | barrier-guards.rb:169:5:169:7 | foo | match |
100+
| barrier-guards.rb:173:6:173:10 | "foo" | barrier-guards.rb:173:13:173:13 | self | no-match |
101+
| barrier-guards.rb:180:6:180:15 | * ... | barrier-guards.rb:181:5:181:7 | foo | match |
102+
| barrier-guards.rb:187:6:187:15 | * ... | barrier-guards.rb:188:5:188:7 | foo | match |
103+
| barrier-guards.rb:191:4:191:15 | ... == ... | barrier-guards.rb:191:4:191:31 | [false] ... or ... | false |
104+
| barrier-guards.rb:191:4:191:15 | ... == ... | barrier-guards.rb:191:20:191:22 | foo | false |
105+
| barrier-guards.rb:191:4:191:31 | [true] ... or ... | barrier-guards.rb:192:5:192:7 | foo | true |
106+
| barrier-guards.rb:191:20:191:31 | ... == ... | barrier-guards.rb:191:4:191:31 | [false] ... or ... | false |

ruby/ql/test/library-tests/dataflow/barrier-guards/barrier-guards.rb

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,74 @@
120120
else
121121
bars
122122
end
123+
124+
case foo
125+
when "foo"
126+
foo
127+
else
128+
foo
129+
end
130+
131+
case foo
132+
when "foo"
133+
foo
134+
when "bar"
135+
foo
136+
end
137+
138+
case foo
139+
when "foo", "bar" # not recognised
140+
foo
141+
when "baz", "quux" # not recognised
142+
foo
143+
else
144+
foo
145+
end
146+
147+
case foo
148+
when *["foo", "bar"]
149+
foo
150+
end
151+
152+
case foo
153+
when *%w[foo bar]
154+
foo
155+
end
156+
157+
case foo
158+
when *FOO
159+
foo
160+
end
161+
162+
case foo
163+
when *foos
164+
foo
165+
end
166+
167+
case foo
168+
when *["foo", x] # not a guard - includes non-constant element `x`
169+
foo
170+
end
171+
172+
case foo
173+
when "foo", x # not a guard - includes non-constant element `x`
174+
foo
175+
end
176+
177+
foo_and_x = ["foo", x]
178+
179+
case foo
180+
when *foo_and_x # not a guard - includes non-constant element `x`
181+
foo
182+
end
183+
184+
FOO_AND_X = ["foo", x]
185+
186+
case foo
187+
when *FOO_AND_X # not a guard - includes non-constant element `x`
188+
foo
189+
end
190+
191+
if foo == "foo" or foo == "bar" # not recognised
192+
foo
193+
end

ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ edges
1010
| CommandInjection.rb:6:15:6:26 | ...[...] : | CommandInjection.rb:34:39:34:51 | "grep #{...}" |
1111
| CommandInjection.rb:46:15:46:20 | call to params : | CommandInjection.rb:46:15:46:26 | ...[...] : |
1212
| CommandInjection.rb:46:15:46:26 | ...[...] : | CommandInjection.rb:50:24:50:36 | "echo #{...}" |
13-
| CommandInjection.rb:64:18:64:23 | number : | CommandInjection.rb:65:14:65:29 | "echo #{...}" |
14-
| CommandInjection.rb:72:23:72:33 | blah_number : | CommandInjection.rb:73:14:73:34 | "echo #{...}" |
15-
| CommandInjection.rb:81:20:81:25 | **args : | CommandInjection.rb:82:22:82:25 | args : |
16-
| CommandInjection.rb:82:22:82:25 | args : | CommandInjection.rb:82:22:82:37 | ...[...] : |
17-
| CommandInjection.rb:82:22:82:37 | ...[...] : | CommandInjection.rb:82:14:82:39 | "echo #{...}" |
18-
| CommandInjection.rb:94:16:94:21 | call to params : | CommandInjection.rb:94:16:94:28 | ...[...] : |
19-
| CommandInjection.rb:94:16:94:28 | ...[...] : | CommandInjection.rb:95:16:95:28 | "cat #{...}" |
13+
| CommandInjection.rb:54:13:54:18 | call to params : | CommandInjection.rb:54:13:54:24 | ...[...] : |
14+
| CommandInjection.rb:54:13:54:24 | ...[...] : | CommandInjection.rb:59:14:59:16 | cmd |
15+
| CommandInjection.rb:73:18:73:23 | number : | CommandInjection.rb:74:14:74:29 | "echo #{...}" |
16+
| CommandInjection.rb:81:23:81:33 | blah_number : | CommandInjection.rb:82:14:82:34 | "echo #{...}" |
17+
| CommandInjection.rb:90:20:90:25 | **args : | CommandInjection.rb:91:22:91:25 | args : |
18+
| CommandInjection.rb:91:22:91:25 | args : | CommandInjection.rb:91:22:91:37 | ...[...] : |
19+
| CommandInjection.rb:91:22:91:37 | ...[...] : | CommandInjection.rb:91:14:91:39 | "echo #{...}" |
20+
| CommandInjection.rb:103:16:103:21 | call to params : | CommandInjection.rb:103:16:103:28 | ...[...] : |
21+
| CommandInjection.rb:103:16:103:28 | ...[...] : | CommandInjection.rb:104:16:104:28 | "cat #{...}" |
2022
nodes
2123
| CommandInjection.rb:6:15:6:20 | call to params : | semmle.label | call to params : |
2224
| CommandInjection.rb:6:15:6:26 | ...[...] : | semmle.label | ...[...] : |
@@ -31,17 +33,20 @@ nodes
3133
| CommandInjection.rb:46:15:46:20 | call to params : | semmle.label | call to params : |
3234
| CommandInjection.rb:46:15:46:26 | ...[...] : | semmle.label | ...[...] : |
3335
| CommandInjection.rb:50:24:50:36 | "echo #{...}" | semmle.label | "echo #{...}" |
34-
| CommandInjection.rb:64:18:64:23 | number : | semmle.label | number : |
35-
| CommandInjection.rb:65:14:65:29 | "echo #{...}" | semmle.label | "echo #{...}" |
36-
| CommandInjection.rb:72:23:72:33 | blah_number : | semmle.label | blah_number : |
37-
| CommandInjection.rb:73:14:73:34 | "echo #{...}" | semmle.label | "echo #{...}" |
38-
| CommandInjection.rb:81:20:81:25 | **args : | semmle.label | **args : |
39-
| CommandInjection.rb:82:14:82:39 | "echo #{...}" | semmle.label | "echo #{...}" |
40-
| CommandInjection.rb:82:22:82:25 | args : | semmle.label | args : |
41-
| CommandInjection.rb:82:22:82:37 | ...[...] : | semmle.label | ...[...] : |
42-
| CommandInjection.rb:94:16:94:21 | call to params : | semmle.label | call to params : |
43-
| CommandInjection.rb:94:16:94:28 | ...[...] : | semmle.label | ...[...] : |
44-
| CommandInjection.rb:95:16:95:28 | "cat #{...}" | semmle.label | "cat #{...}" |
36+
| CommandInjection.rb:54:13:54:18 | call to params : | semmle.label | call to params : |
37+
| CommandInjection.rb:54:13:54:24 | ...[...] : | semmle.label | ...[...] : |
38+
| CommandInjection.rb:59:14:59:16 | cmd | semmle.label | cmd |
39+
| CommandInjection.rb:73:18:73:23 | number : | semmle.label | number : |
40+
| CommandInjection.rb:74:14:74:29 | "echo #{...}" | semmle.label | "echo #{...}" |
41+
| CommandInjection.rb:81:23:81:33 | blah_number : | semmle.label | blah_number : |
42+
| CommandInjection.rb:82:14:82:34 | "echo #{...}" | semmle.label | "echo #{...}" |
43+
| CommandInjection.rb:90:20:90:25 | **args : | semmle.label | **args : |
44+
| CommandInjection.rb:91:14:91:39 | "echo #{...}" | semmle.label | "echo #{...}" |
45+
| CommandInjection.rb:91:22:91:25 | args : | semmle.label | args : |
46+
| CommandInjection.rb:91:22:91:37 | ...[...] : | semmle.label | ...[...] : |
47+
| CommandInjection.rb:103:16:103:21 | call to params : | semmle.label | call to params : |
48+
| CommandInjection.rb:103:16:103:28 | ...[...] : | semmle.label | ...[...] : |
49+
| CommandInjection.rb:104:16:104:28 | "cat #{...}" | semmle.label | "cat #{...}" |
4550
subpaths
4651
#select
4752
| CommandInjection.rb:7:10:7:15 | #{...} | CommandInjection.rb:6:15:6:20 | call to params : | CommandInjection.rb:7:10:7:15 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value |
@@ -53,7 +58,8 @@ subpaths
5358
| CommandInjection.rb:33:24:33:36 | "echo #{...}" | CommandInjection.rb:6:15:6:20 | call to params : | CommandInjection.rb:33:24:33:36 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value |
5459
| CommandInjection.rb:34:39:34:51 | "grep #{...}" | CommandInjection.rb:6:15:6:20 | call to params : | CommandInjection.rb:34:39:34:51 | "grep #{...}" | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value |
5560
| CommandInjection.rb:50:24:50:36 | "echo #{...}" | CommandInjection.rb:46:15:46:20 | call to params : | CommandInjection.rb:50:24:50:36 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:46:15:46:20 | call to params | user-provided value |
56-
| CommandInjection.rb:65:14:65:29 | "echo #{...}" | CommandInjection.rb:64:18:64:23 | number : | CommandInjection.rb:65:14:65:29 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:64:18:64:23 | number | user-provided value |
57-
| CommandInjection.rb:73:14:73:34 | "echo #{...}" | CommandInjection.rb:72:23:72:33 | blah_number : | CommandInjection.rb:73:14:73:34 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:72:23:72:33 | blah_number | user-provided value |
58-
| CommandInjection.rb:82:14:82:39 | "echo #{...}" | CommandInjection.rb:81:20:81:25 | **args : | CommandInjection.rb:82:14:82:39 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:81:20:81:25 | **args | user-provided value |
59-
| CommandInjection.rb:95:16:95:28 | "cat #{...}" | CommandInjection.rb:94:16:94:21 | call to params : | CommandInjection.rb:95:16:95:28 | "cat #{...}" | This command depends on a $@. | CommandInjection.rb:94:16:94:21 | call to params | user-provided value |
61+
| CommandInjection.rb:59:14:59:16 | cmd | CommandInjection.rb:54:13:54:18 | call to params : | CommandInjection.rb:59:14:59:16 | cmd | This command depends on a $@. | CommandInjection.rb:54:13:54:18 | call to params | user-provided value |
62+
| CommandInjection.rb:74:14:74:29 | "echo #{...}" | CommandInjection.rb:73:18:73:23 | number : | CommandInjection.rb:74:14:74:29 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:73:18:73:23 | number | user-provided value |
63+
| CommandInjection.rb:82:14:82:34 | "echo #{...}" | CommandInjection.rb:81:23:81:33 | blah_number : | CommandInjection.rb:82:14:82:34 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:81:23:81:33 | blah_number | user-provided value |
64+
| CommandInjection.rb:91:14:91:39 | "echo #{...}" | CommandInjection.rb:90:20:90:25 | **args : | CommandInjection.rb:91:14:91:39 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:90:20:90:25 | **args | user-provided value |
65+
| CommandInjection.rb:104:16:104:28 | "cat #{...}" | CommandInjection.rb:103:16:103:21 | call to params : | CommandInjection.rb:104:16:104:28 | "cat #{...}" | This command depends on a $@. | CommandInjection.rb:103:16:103:21 | call to params | user-provided value |

0 commit comments

Comments
 (0)