|
1 | 1 | import actions
|
| 2 | +import codeql.actions.config.Config |
2 | 3 |
|
3 | 4 | abstract class PoisonableStep extends Step { }
|
4 | 5 |
|
5 |
| -// source: https://github.com/boostsecurityio/poutine/blob/main/opa/rego/rules/untrusted_checkout_exec.rego#L16 |
6 | 6 | private string dangerousActions() {
|
7 |
| - result = |
8 |
| - [ |
9 |
| - "pre-commit/action", "oxsecurity/megalinter", "bridgecrewio/checkov-action", |
10 |
| - "ruby/setup-ruby", "actions/jekyll-build-pages" |
11 |
| - ] |
| 7 | + exists(string action | |
| 8 | + poisonableActionsDataModel(action) and |
| 9 | + result = action |
| 10 | + ) |
12 | 11 | }
|
13 | 12 |
|
14 | 13 | class DangerousActionUsesStep extends PoisonableStep, UsesStep {
|
15 | 14 | DangerousActionUsesStep() { this.getCallee() = dangerousActions() }
|
16 | 15 | }
|
17 | 16 |
|
18 |
| -// source: https://github.com/boostsecurityio/poutine/blob/main/opa/rego/rules/untrusted_checkout_exec.rego#L23 |
19 |
| -private string dangerousCommands() { |
20 |
| - result = |
21 |
| - [ |
22 |
| - "npm i(nstall)?(\\b|$)", "npm run ", "yarn ", "npm ci(\\b|$)", "make ", "terraform plan", |
23 |
| - "terraform apply", "gomplate ", "pre-commit run", "pre-commit install", "go generate", |
24 |
| - "msbuild ", "mvn ", "gradle ", "bundle install", "bundle exec ", "^ant ", "mkdocs build", |
25 |
| - "pytest", "pip install -r ", "pip install --requirement", "java -jar ", "poetry install", |
26 |
| - "poetry run", "cargo " |
27 |
| - ] |
28 |
| -} |
29 |
| - |
30 |
| -class BuildRunStep extends PoisonableStep, Run { |
31 |
| - BuildRunStep() { |
32 |
| - exists( |
33 |
| - this.getScript().splitAt("\n").trim().regexpFind("([^a-z]|^)" + dangerousCommands(), _, _) |
| 17 | +class PoisonableCommandStep extends PoisonableStep, Run { |
| 18 | + PoisonableCommandStep() { |
| 19 | + exists(string regexp | |
| 20 | + poisonableCommandsDataModel(regexp) and |
| 21 | + exists(this.getScript().splitAt("\n").trim().regexpFind("([^a-z]|^)" + regexp, _, _)) |
34 | 22 | )
|
35 | 23 | }
|
36 | 24 | }
|
37 | 25 |
|
38 |
| -bindingset[cmdRegexp] |
39 |
| -string wrapLocalCmd(string cmdRegexp) { result = "(^|;\\s*|\\s+)" + cmdRegexp + "(\\s+|;|$)" } |
40 |
| - |
41 |
| -class LocalCommandExecutionRunStep extends PoisonableStep, Run { |
| 26 | +class LocalScriptExecutionRunStep extends PoisonableStep, Run { |
42 | 27 | string cmd;
|
43 | 28 |
|
44 |
| - LocalCommandExecutionRunStep() { |
45 |
| - // Heuristic: |
46 |
| - exists(string line | line = this.getScript().splitAt("\n").trim() | |
47 |
| - // ./xxxx |
48 |
| - // TODO: It could also be in the form of `dir/cmd` |
49 |
| - cmd = line.regexpCapture(wrapLocalCmd("\\.\\/(.*)"), 2) |
50 |
| - or |
51 |
| - // sh xxxx |
52 |
| - cmd = line.regexpCapture(wrapLocalCmd("(ba|z|fi)?sh\\s+(.*)"), 3) |
53 |
| - or |
54 |
| - // node xxxx.js |
55 |
| - cmd = line.regexpCapture(wrapLocalCmd("node\\s+(.*)(\\.js|\\.ts)"), 2) |
56 |
| - or |
57 |
| - // python xxxx.py |
58 |
| - cmd = line.regexpCapture(wrapLocalCmd("python\\s+(.*)\\.py"), 2) |
59 |
| - or |
60 |
| - // ruby xxxx.rb |
61 |
| - cmd = line.regexpCapture(wrapLocalCmd("ruby\\s+(.*)\\.rb"), 2) |
62 |
| - or |
63 |
| - // go xxxx.go |
64 |
| - cmd = line.regexpCapture(wrapLocalCmd("go\\s+(.*)\\.go"), 2) |
| 29 | + LocalScriptExecutionRunStep() { |
| 30 | + exists(string line, string regexp, int group | line = this.getScript().splitAt("\n").trim() | |
| 31 | + poisonableLocalScriptsDataModel(regexp, group) and |
| 32 | + cmd = line.regexpCapture(regexp, group) |
65 | 33 | )
|
66 | 34 | }
|
67 | 35 |
|
|
0 commit comments