Skip to content

Commit c84e64e

Browse files
author
Alvaro Muñoz
authored
Merge pull request #16 from GitHubSecurityLab/model-gen-queries
feat(model-generation): Add more model generation queries
2 parents 334fda1 + 1d582a4 commit c84e64e

7 files changed

+177
-3
lines changed

ql/lib/codeql/actions/Ast.qll

+4-1
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,10 @@ private string jobsCtxRegex() {
369369

370370
private string envCtxRegex() { result = "\\benv\\.([A-Za-z0-9_-]+)\\b" }
371371

372-
private string inputsCtxRegex() { result = "\\binputs\\.([A-Za-z0-9_-]+)\\b" }
372+
private string inputsCtxRegex() {
373+
result = "\\binputs\\.([A-Za-z0-9_-]+)\\b" or
374+
result = "\\bgithub\\.event\\.inputs\\.([A-Za-z0-9_-]+)\\b"
375+
}
373376

374377
/**
375378
* Holds for an expression accesing the `steps` context.

ql/src/Security/CWE-020/CompositeActionSummaries.ql

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,7 @@ module MyFlow = TaintTracking::Global<MyConfig>;
3131
import MyFlow::PathGraph
3232

3333
from MyFlow::PathNode source, MyFlow::PathNode sink
34-
where MyFlow::flowPath(source, sink)
34+
where
35+
MyFlow::flowPath(source, sink) and
36+
source.getNode().getLocation().getFile() = sink.getNode().getLocation().getFile()
3537
select sink.getNode(), source, sink, "Summary"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* @name Composite Action Sinks
3+
* @description Actions passing input variables to expression injection sinks.
4+
* @kind path-problem
5+
* @problem.severity warning
6+
* @security-severity 9.3
7+
* @precision high
8+
* @id actions/composite-action-sinks
9+
* @tags actions
10+
* model-generator
11+
* external/cwe/cwe-020
12+
*/
13+
14+
import actions
15+
import codeql.actions.TaintTracking
16+
import codeql.actions.dataflow.FlowSources
17+
import codeql.actions.dataflow.ExternalFlow
18+
19+
private class ExpressionInjectionSink extends DataFlow::Node {
20+
ExpressionInjectionSink() {
21+
exists(RunExpr e | e.getScriptExpr() = this.asExpr()) or
22+
externallyDefinedSink(this, "expression-injection")
23+
}
24+
}
25+
26+
private module MyConfig implements DataFlow::ConfigSig {
27+
predicate isSource(DataFlow::Node source) {
28+
exists(CompositeActionStmt c | c.getInputsStmt().getInputExpr(_) = source.asExpr())
29+
}
30+
31+
predicate isSink(DataFlow::Node sink) { sink instanceof ExpressionInjectionSink }
32+
}
33+
34+
module MyFlow = TaintTracking::Global<MyConfig>;
35+
36+
import MyFlow::PathGraph
37+
38+
from MyFlow::PathNode source, MyFlow::PathNode sink
39+
where
40+
MyFlow::flowPath(source, sink) and
41+
source.getNode().getLocation().getFile() = sink.getNode().getLocation().getFile()
42+
select sink.getNode(), source, sink, "Sink"

ql/src/Security/CWE-020/CompositeActionsSources.ql

+3-1
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,7 @@ module MyFlow = TaintTracking::Global<MyConfig>;
4040
import MyFlow::PathGraph
4141

4242
from MyFlow::PathNode source, MyFlow::PathNode sink
43-
where MyFlow::flowPath(source, sink)
43+
where
44+
MyFlow::flowPath(source, sink) and
45+
source.getNode().getLocation().getFile() = sink.getNode().getLocation().getFile()
4446
select sink.getNode(), source, sink, "Source"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* @name Reusable Workflow Sinks
3+
* @description Reusable Workflows passing parameters to an expression injection sink.
4+
* @kind path-problem
5+
* @problem.severity warning
6+
* @security-severity 9.3
7+
* @precision high
8+
* @id actions/reusable-wokflow-sinks
9+
* @tags actions
10+
* model-generator
11+
* external/cwe/cwe-020
12+
*/
13+
14+
import actions
15+
import codeql.actions.TaintTracking
16+
import codeql.actions.dataflow.FlowSources
17+
import codeql.actions.dataflow.ExternalFlow
18+
19+
private class ExpressionInjectionSink extends DataFlow::Node {
20+
ExpressionInjectionSink() {
21+
exists(RunExpr e | e.getScriptExpr() = this.asExpr()) or
22+
externallyDefinedSink(this, "expression-injection")
23+
}
24+
}
25+
26+
private module MyConfig implements DataFlow::ConfigSig {
27+
predicate isSource(DataFlow::Node source) {
28+
exists(ReusableWorkflowStmt w | w.getInputsStmt().getInputExpr(_) = source.asExpr())
29+
}
30+
31+
predicate isSink(DataFlow::Node sink) { sink instanceof ExpressionInjectionSink }
32+
}
33+
34+
module MyFlow = TaintTracking::Global<MyConfig>;
35+
36+
import MyFlow::PathGraph
37+
38+
from MyFlow::PathNode source, MyFlow::PathNode sink
39+
where
40+
MyFlow::flowPath(source, sink) and
41+
source.getNode().getLocation().getFile() = sink.getNode().getLocation().getFile()
42+
select sink.getNode(), source, sink, "Sink"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* @name Reusable Workflow Sources
3+
* @description Reusable Workflow that pass user-controlled data to their output variables.
4+
* @kind path-problem
5+
* @problem.severity warning
6+
* @security-severity 9.3
7+
* @precision high
8+
* @id actions/reusable-workflow-sources
9+
* @tags actions
10+
* model-generator
11+
* external/cwe/cwe-020
12+
*/
13+
14+
import actions
15+
import codeql.actions.TaintTracking
16+
import codeql.actions.dataflow.FlowSources
17+
import codeql.actions.dataflow.ExternalFlow
18+
19+
private module MyConfig implements DataFlow::ConfigSig {
20+
predicate isSource(DataFlow::Node source) {
21+
source instanceof RemoteFlowSource and
22+
not source instanceof DataFlow::ParameterNode and
23+
exists(ReusableWorkflowStmt w | w.getAChildNode*() = source.asExpr())
24+
}
25+
26+
predicate isSink(DataFlow::Node sink) {
27+
exists(ReusableWorkflowStmt w | w.getOutputsStmt().getOutputExpr(_) = sink.asExpr())
28+
}
29+
30+
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet set) {
31+
allowImplicitRead(node, set)
32+
or
33+
isSink(node) and
34+
set instanceof DataFlow::FieldContent
35+
}
36+
}
37+
38+
module MyFlow = TaintTracking::Global<MyConfig>;
39+
40+
import MyFlow::PathGraph
41+
42+
from MyFlow::PathNode source, MyFlow::PathNode sink
43+
where
44+
MyFlow::flowPath(source, sink) and
45+
source.getNode().getLocation().getFile() = sink.getNode().getLocation().getFile()
46+
select sink.getNode(), source, sink, "Source"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* @name Reusable Workflows Summaries
3+
* @description Reusable workflow that pass user-controlled data to their output variables.
4+
* @kind path-problem
5+
* @problem.severity warning
6+
* @security-severity 9.3
7+
* @precision high
8+
* @id actions/reusable-workflow-summaries
9+
* @tags actions
10+
* model-generator
11+
* external/cwe/cwe-020
12+
*/
13+
14+
import actions
15+
import codeql.actions.TaintTracking
16+
import codeql.actions.dataflow.FlowSources
17+
import codeql.actions.dataflow.ExternalFlow
18+
19+
private module MyConfig implements DataFlow::ConfigSig {
20+
predicate isSource(DataFlow::Node source) {
21+
exists(ReusableWorkflowStmt w | w.getInputsStmt().getInputExpr(_) = source.asExpr())
22+
}
23+
24+
predicate isSink(DataFlow::Node sink) {
25+
exists(ReusableWorkflowStmt w | w.getOutputsStmt().getOutputExpr(_) = sink.asExpr())
26+
}
27+
}
28+
29+
module MyFlow = TaintTracking::Global<MyConfig>;
30+
31+
import MyFlow::PathGraph
32+
33+
from MyFlow::PathNode source, MyFlow::PathNode sink
34+
where
35+
MyFlow::flowPath(source, sink) and
36+
source.getNode().getLocation().getFile() = sink.getNode().getLocation().getFile()
37+
select sink.getNode(), source, sink, "Summary"

0 commit comments

Comments
 (0)