|
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