From 598e1889ea0ca95965cc3678c51a2066261aada6 Mon Sep 17 00:00:00 2001 From: Sebastien Graveline Date: Fri, 18 Apr 2025 14:21:01 -0400 Subject: [PATCH] Add lotp + local gha --- opa/rego/rules/untrusted_checkout_exec.rego | 77 +++++++++++++++++++-- scanner/inventory_test.go | 45 +++++++++++- 2 files changed, 114 insertions(+), 8 deletions(-) diff --git a/opa/rego/rules/untrusted_checkout_exec.rego b/opa/rego/rules/untrusted_checkout_exec.rego index ccfed28..21c4953 100644 --- a/opa/rego/rules/untrusted_checkout_exec.rego +++ b/opa/rego/rules/untrusted_checkout_exec.rego @@ -15,6 +15,7 @@ rule := poutine.rule(rego.metadata.chain()) github.events contains event if some event in { "pull_request_target", + "issues", "issue_comment", "workflow_call", } @@ -22,32 +23,77 @@ github.events contains event if some event in { github.workflow_run.parent.events contains event if some event in { "pull_request_target", "pull_request", + "issues", + "issue_comment", } build_github_actions[action] = { - "pre-commit/action": "pre-commit", - "oxsecurity/megalinter": "megalinter", - "bridgecrewio/checkov-action": "checkov", - "ruby/setup-ruby": "bundler", + "bundler":{"ruby/setup-ruby"}, + "cargo":{"actions-rs/cargo"}, + "checkov":{"bridgecrewio/checkov-action"}, + "docker":{"docker/build-push-action", "docker/setup-buildx-action"}, + "eslint":{"reviewdog/action-eslint", "stefanoeb/eslint-action", "tj-actions/eslint-changed-files", "sibiraj-s/action-eslint", "tinovyatkin/action-eslint", "bradennapier/eslint-plus-action", "CatChen/eslint-suggestion-action", "iCrawl/action-eslint", "ninosaurus/eslint-check"}, + "golangci-lint":{"golangci/golangci-lint-action"}, + "goreleaser": {"goreleaser/goreleaser-action"}, + "gradle": {"gradle/gradle-build-action"}, + "maven": {"qcastel/github-actions-maven-release", "samuelmeuli/action-maven-publish", "LucaFeger/action-maven-cli"}, + "megalinter":{"oxsecurity/megalinter"}, + "mkdocs": {"mhausenblas/mkdocs-deploy-gh-pages", "athackst/mkdocs-simple-plugin"}, + "msbuild": {"MVS-Telecom/publish-nuget"}, + "mypy": {"ricardochaves/python-lint", "jpetrucciani/mypy-check", "sunnysid3up/python-linter", "tsuyoshicho/action-mypy"}, + "npm": {"actions/setup-node","JS-DevTools/npm-publish"}, + "phpstan":{"php-actions/phpstan"}, + "pip": {"brettcannon/pip-secure-install", "BSFishy/pip-action"}, + "pre-commit": {"dbt-checkpoint/dbt-checkpoint", "pre-commit/action", "pre-commit-ci/lite-action", "browniebroke/pre-commit-autoupdate-action", "cloudposse/github-action-pre-commit"}, + "pre-commit":{"pre-commit/action"}, + "python": {"hynek/build-and-inspect-python-package"}, + "rake": {"magefile/mage-action"}, + "rubocop": {"reviewdog/action-rubocop", "andrewmcodes-archive/rubocop-linter-action", "gimenete/rubocop-action", "r7kamura/rubocop-todo-corrector"}, + "sonar-scanner": {"sonarsource/sonarqube-scan-action"}, + "stylelint":{"actions-hub/stylelint"}, + "terraform": {"OP5dev/TF-via-PR", "dflook/terraform-plan", "dflook/terraform-apply"}, + "tflint": {"reviewdog/action-tflint", "devops-infra/action-tflint"}, + "tofu": {"dflook/tofu-plan", "dflook/tofu-apply"}, + "vale": {"gaurav-nelson/github-action-vale-lint", "errata-ai/vale-action"}, }[action] build_commands[cmd] = { "ant": {"^ant "}, + "bash": {"\\S+\\.sh\\b"}, "bundler": {"bundle install", "bundle exec "}, - "cargo": {"cargo build", "cargo run"}, + "cargo": {"cargo build", "cargo run", "cargo test", "cargo bench"}, + "checkov": {"checkov "}, + "chmod": {"^\\s*chmod\\s+(?:.*\\+x.*|\\b(?:[0-7]{2}[1357]|[0-7][0-7]{2}[1357])\\b)"}, # Unit test: https://regex101.com/r/tt7qzw/1 + "docker": {"docker build"}, # docker build need to also be run to have significant impact. + "eslint": {"eslint "}, "go generate": {"go generate"}, "gomplate": {"gomplate "}, + "goreleaser": {"goreleaser build", "goreleaser release"}, "gradle": {"gradle ", "./gradlew ", "./gradlew.bat "}, # https://docs.gradle.org/current/userguide/gradle_wrapper_basics.html "make": {"make "}, "maven": {"mvn ", "./mvnw ", "./mvnw.bat", "./mvnw.cmd", "./mvnw.sh "}, # https://maven.apache.org/wrapper/ "mkdocs": {"mkdocs build"}, "msbuild": {"msbuild "}, - "npm": {"npm install", "npm run ", "yarn ", "npm ci(\\b|$)"}, + "mypy": {"mypy "}, + "npm": {"npm diff", "npm restart", "npm (rum|urn|run(-script)?)", "npm start", "npm stop", "npm t(e?st)?", "npm ver(si|is)on","npm (install|add|i|in|ins|inst|insta|instal|inst|isnta|isntal|isntall)", "npm ci(\\b|$)"}, + "phpstan": {"phpstan "}, "pip": {"pip install", "pipenv install", "pipenv run "}, + "powershell": {"\\S+\\.ps1\\b"}, "pre-commit": {"pre-commit run", "pre-commit install"}, + "python": {"^\\s*python(3)?\\s+\\S+\\.py\\b"}, # Unit test: https://regex101.com/r/tuap3y/1 + "rake": {"rails db:create", "rails assets:precompile", "^rake "}, + "rubocop": {"rubocop"}, + "sonar-scanner": {"sonar-scanner"}, + "stylelint": {"stylelint "}, + "tar": {"tar (-?x-?P-?f|-?P-?x-?f|-?x -P -f|-?P -x -f) "}, # Unit test: https://regex101.com/r/pX85P8/1 "terraform": {"terraform plan", "terraform apply"}, + "tflint": {"tflint"}, "tofu": {"tofu plan", "tofu apply"}, + "trivy": {"trivy "}, + "unzip": {"unzip .*-:"}, "vale": {"vale "}, + "webpack": {"webpack"}, + "yarn": {"yarn "}, }[cmd] results contains poutine.finding(rule, pkg_purl, { @@ -70,7 +116,24 @@ results contains poutine.finding(rule, pkg_purl, { "event_triggers": workflow_events, }) if { [pkg_purl, workflow_path, workflow_events, step] := _steps_after_untrusted_checkout[_] - build_github_actions[step.action] + regex.match( + sprintf("([^a-z]|^)(%v)@", [concat("|", build_github_actions[_])]), + step.uses, + ) +} + + +results contains poutine.finding(rule, pkg_purl, { + "path": workflow_path, + "line": step.lines.uses, + "details": sprintf("Detected usage of a Local GitHub Action at path: `%s`", [step.action]), + "event_triggers": workflow_events, +}) if { + [pkg_purl, workflow_path, workflow_events, step] := _steps_after_untrusted_checkout[_] + regex.match( + `^\./`, + step.action, + ) } _steps_after_untrusted_checkout contains [pkg.purl, workflow.path, events, s.step] if { diff --git a/scanner/inventory_test.go b/scanner/inventory_test.go index 1222bfc..80d1250 100644 --- a/scanner/inventory_test.go +++ b/scanner/inventory_test.go @@ -2,9 +2,10 @@ package scanner import ( "context" - "github.com/boostsecurityio/poutine/results" "testing" + "github.com/boostsecurityio/poutine/results" + "github.com/boostsecurityio/poutine/models" "github.com/boostsecurityio/poutine/opa" "github.com/stretchr/testify/assert" @@ -216,6 +217,26 @@ func TestFindings(t *testing.T) { EventTriggers: []string{"push", "pull_request_target"}, }, }, + { + RuleId: "untrusted_checkout_exec", + Purl: purl, + Meta: results.FindingMeta{ + Path: ".github/workflows/valid.yml", + Line: 75, + Details: "Detected usage of `bash`", + EventTriggers: []string{"push", "pull_request_target"}, + }, + }, + { + RuleId: "untrusted_checkout_exec", + Purl: purl, + Meta: results.FindingMeta{ + Path: ".github/workflows/valid.yml", + Line: 80, + Details: "Detected usage of `bash`", + EventTriggers: []string{"push", "pull_request_target"}, + }, + }, { RuleId: "untrusted_checkout_exec", Purl: purl, @@ -403,6 +424,17 @@ func TestFindings(t *testing.T) { Details: "system.debug", }, }, + { + RuleId: "untrusted_checkout_exec", + Purl: purl, + Meta: results.FindingMeta{ + Path: "azure-pipelines-2.yml", + Line: 13, + Job: "", + Step: "1", + Details: "Detected usage of `bash`", + }, + }, { RuleId: "untrusted_checkout_exec", Purl: purl, @@ -414,6 +446,17 @@ func TestFindings(t *testing.T) { Details: "Detected usage of `npm`", }, }, + { + RuleId: "untrusted_checkout_exec", + Purl: purl, + Meta: results.FindingMeta{ + Path: "azure-pipelines-4.yml", + Line: 10, + Job: "", + Step: "1", + Details: "Detected usage of `bash`", + }, + }, { RuleId: "untrusted_checkout_exec", Purl: purl,