From 1233d81523e40bec36476573ac2b4dcbcd82dc85 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 15 Apr 2026 14:11:17 -0400 Subject: [PATCH 1/5] Improve actions/ql/src/Security/CWE-829/UntrustedCheckoutX queries --- actions/ql/lib/ext/config/poisonable_steps.yml | 4 ++-- .../src/Security/CWE-094/CodeInjectionMedium.ql | 17 +++++++++++------ .../CWE-829/UntrustedCheckoutCritical.md | 3 ++- .../CWE-829/UntrustedCheckoutCritical.ql | 2 +- .../Security/CWE-829/UntrustedCheckoutHigh.md | 3 ++- .../Security/CWE-829/UntrustedCheckoutHigh.ql | 2 +- .../Security/CWE-829/UntrustedCheckoutMedium.md | 3 ++- ...026-04-15-untrusted-checkout-improvements.md | 6 ++++++ 8 files changed, 27 insertions(+), 13 deletions(-) create mode 100644 actions/ql/src/change-notes/2026-04-15-untrusted-checkout-improvements.md diff --git a/actions/ql/lib/ext/config/poisonable_steps.yml b/actions/ql/lib/ext/config/poisonable_steps.yml index 3c1aec70a240..d15b8d7a6a5f 100644 --- a/actions/ql/lib/ext/config/poisonable_steps.yml +++ b/actions/ql/lib/ext/config/poisonable_steps.yml @@ -70,7 +70,7 @@ extensions: - ["(source|sh|bash|zsh|fish)\\s+([^\\s]+)\\b", 2] - ["(node)\\s+([^\\s]+)(\\.js|\\.ts)\\b", 2] - ["(python[\\d\\.]*)\\s+([^\\s]+)\\.py\\b", 2] + - ["(python[\\d\\.]*)\\s+([\\-m]+)\\s+(\\w+)\\b", 2] # eg: pythonX -m anything(dir or file) - ["(ruby)\\s+([^\\s]+)\\.rb\\b", 2] - - ["(go)\\s+(generate|run)\\s+([^\\s]+)\\.go\\b", 3] + - ["(go)\\s+(generate|run)\\s+([^\\s]+)", 3] - ["(dotnet)\\s+([^\\s]+)\\.csproj\\b", 2] - diff --git a/actions/ql/src/Security/CWE-094/CodeInjectionMedium.ql b/actions/ql/src/Security/CWE-094/CodeInjectionMedium.ql index 8bc3fe8f51ad..22ab430105a3 100644 --- a/actions/ql/src/Security/CWE-094/CodeInjectionMedium.ql +++ b/actions/ql/src/Security/CWE-094/CodeInjectionMedium.ql @@ -2,7 +2,7 @@ * @name Code injection * @description Interpreting unsanitized user input as code allows a malicious user to perform arbitrary * code execution. - * @kind path-problem + * @ kind path-problem * @problem.severity warning * @security-severity 5.0 * @precision medium @@ -18,8 +18,13 @@ import actions import codeql.actions.security.CodeInjectionQuery import CodeInjectionFlow::PathGraph -from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink -where mediumSeverityCodeInjection(source, sink) -select sink.getNode(), source, sink, - "Potential code injection in $@, which may be controlled by an external user.", sink, - sink.getNode().asExpr().(Expression).getRawExpression() +// from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink +// where mediumSeverityCodeInjection(source, sink) +// select sink.getNode(), source, sink, +// "Potential code injection in $@, which may be controlled by an external user.", sink, +// sink.getNode().asExpr().(Expression).getRawExpression() +from string test +where + test.regexpMatch("(python[\\d\\.]*)\\s+([^\\s]+)\\.py\\b") and + test = "python -m dir" //go run main/main.go //go run . +select test diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.md b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.md index 6060354b134a..246e302e85b8 100644 --- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.md +++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.md @@ -1,6 +1,6 @@ ## Overview -GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A potentially dangerous misuse of the triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted code (Pull Request HEAD) may lead to repository compromise if untrusted code gets executed (e.g., due to a modified build script) in a privileged job. +GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A dangerous misuse of event triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted input from the PR may lead to repository compromise if untrusted code gets executed in a privileged job. Untrusted code may get executed due to a modified build script, workflow injection, or registry hijacking. **Carefully review** whether least privileges is used and whether input is taken from untrusted sources. ## Recommendation @@ -133,3 +133,4 @@ jobs: ## References - GitHub Security Lab Research: [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/). +- Living Off the Pipeline: [LOTP](https://boostsecurityio.github.io/lotp/). \ No newline at end of file diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql index ad79a1ce776f..8e8882f9cf5f 100644 --- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql +++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql @@ -51,5 +51,5 @@ where event.getName() = checkoutTriggers() and not exists(ControlCheck check | check.protects(checkout, event, "untrusted-checkout")) and not exists(ControlCheck check | check.protects(poisonable, event, "untrusted-checkout")) -select poisonable, checkout, poisonable, +select checkout, checkout, poisonable, "Potential execution of untrusted code on a privileged workflow ($@)", event, event.getName() diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.md b/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.md index 6060354b134a..f412421b7f1d 100644 --- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.md +++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.md @@ -1,6 +1,6 @@ ## Overview -GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A potentially dangerous misuse of the triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted code (Pull Request HEAD) may lead to repository compromise if untrusted code gets executed (e.g., due to a modified build script) in a privileged job. +GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A dangerous misuse of event triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted input from the PR may lead to repository compromise if untrusted code gets executed in a privileged job. Untrusted code may get executed due to a modified build script, workflow injection, or registry hijacking. **Carefully review** whether least privileges is used and whether input is taken from untrusted sources. ## Recommendation @@ -133,3 +133,4 @@ jobs: ## References - GitHub Security Lab Research: [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/). +- Living Off the Pipeline: [LOTP](https://boostsecurityio.github.io/lotp/). \ No newline at end of file diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql b/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql index 98b9aee33f77..5c2d4b3d56c8 100644 --- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql +++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.ql @@ -1,5 +1,5 @@ /** - * @name Checkout of untrusted code in trusted context + * @name Checkout of untrusted code in privileged context without privileged context use * @description Privileged workflows have read/write access to the base repository and access to secrets. * By explicitly checking out and running the build script from a fork the untrusted code is running in an environment * that is able to push to the base repository and to access secrets. diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutMedium.md b/actions/ql/src/Security/CWE-829/UntrustedCheckoutMedium.md index 6060354b134a..246e302e85b8 100644 --- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutMedium.md +++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutMedium.md @@ -1,6 +1,6 @@ ## Overview -GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A potentially dangerous misuse of the triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted code (Pull Request HEAD) may lead to repository compromise if untrusted code gets executed (e.g., due to a modified build script) in a privileged job. +GitHub workflows can be triggered through various repository events, including incoming pull requests (PRs) or comments on Issues/PRs. A dangerous misuse of event triggers such as `pull_request_target` or `issue_comment` followed by an explicit checkout of untrusted input from the PR may lead to repository compromise if untrusted code gets executed in a privileged job. Untrusted code may get executed due to a modified build script, workflow injection, or registry hijacking. **Carefully review** whether least privileges is used and whether input is taken from untrusted sources. ## Recommendation @@ -133,3 +133,4 @@ jobs: ## References - GitHub Security Lab Research: [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/). +- Living Off the Pipeline: [LOTP](https://boostsecurityio.github.io/lotp/). \ No newline at end of file diff --git a/actions/ql/src/change-notes/2026-04-15-untrusted-checkout-improvements.md b/actions/ql/src/change-notes/2026-04-15-untrusted-checkout-improvements.md new file mode 100644 index 000000000000..ef16e84e2c21 --- /dev/null +++ b/actions/ql/src/change-notes/2026-04-15-untrusted-checkout-improvements.md @@ -0,0 +1,6 @@ +--- +category: majorAnalysis +--- +* Fixed help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Previously the messages were unclear as to why and how the vulnerabilities could occur. Additionally alter 2 patterns in the detection such that now extra sinks are detected in the following cases: scripts executed via python modules and `go run` in directories are detected as potential mechanisms of injection. This may lead to more results being detected by all 3 queries. +* Adjusted `actions/untrusted-checkout/critical` to align more with other untrusted resource queries, where the alert location is the location where the artifact is obtained from (the checkout point). This aligns with the other 2 related queries. This will cause the same alerts to re-open for closed alerts of this query. +* Adjusted the name of `actions/untrusted-checkout/high` to more clearly describe which parts of the scenario are in a privileged context. This will cause the same alerts to re-open for closed alerts of this query. \ No newline at end of file From a342efca0e6e04889b87be3925db7b13d00e3a9a Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 15 Apr 2026 16:12:52 -0400 Subject: [PATCH 2/5] Revert accidental change --- .../src/Security/CWE-094/CodeInjectionMedium.ql | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/actions/ql/src/Security/CWE-094/CodeInjectionMedium.ql b/actions/ql/src/Security/CWE-094/CodeInjectionMedium.ql index 22ab430105a3..8bc3fe8f51ad 100644 --- a/actions/ql/src/Security/CWE-094/CodeInjectionMedium.ql +++ b/actions/ql/src/Security/CWE-094/CodeInjectionMedium.ql @@ -2,7 +2,7 @@ * @name Code injection * @description Interpreting unsanitized user input as code allows a malicious user to perform arbitrary * code execution. - * @ kind path-problem + * @kind path-problem * @problem.severity warning * @security-severity 5.0 * @precision medium @@ -18,13 +18,8 @@ import actions import codeql.actions.security.CodeInjectionQuery import CodeInjectionFlow::PathGraph -// from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink -// where mediumSeverityCodeInjection(source, sink) -// select sink.getNode(), source, sink, -// "Potential code injection in $@, which may be controlled by an external user.", sink, -// sink.getNode().asExpr().(Expression).getRawExpression() -from string test -where - test.regexpMatch("(python[\\d\\.]*)\\s+([^\\s]+)\\.py\\b") and - test = "python -m dir" //go run main/main.go //go run . -select test +from CodeInjectionFlow::PathNode source, CodeInjectionFlow::PathNode sink +where mediumSeverityCodeInjection(source, sink) +select sink.getNode(), source, sink, + "Potential code injection in $@, which may be controlled by an external user.", sink, + sink.getNode().asExpr().(Expression).getRawExpression() From c9e5dbda782fea39790bd736bebaa8a15d59226d Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 15 Apr 2026 16:26:38 -0400 Subject: [PATCH 3/5] Update actions/ql/lib/ext/config/poisonable_steps.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- actions/ql/lib/ext/config/poisonable_steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/ql/lib/ext/config/poisonable_steps.yml b/actions/ql/lib/ext/config/poisonable_steps.yml index d15b8d7a6a5f..cf7f71dccc94 100644 --- a/actions/ql/lib/ext/config/poisonable_steps.yml +++ b/actions/ql/lib/ext/config/poisonable_steps.yml @@ -72,5 +72,5 @@ extensions: - ["(python[\\d\\.]*)\\s+([^\\s]+)\\.py\\b", 2] - ["(python[\\d\\.]*)\\s+([\\-m]+)\\s+(\\w+)\\b", 2] # eg: pythonX -m anything(dir or file) - ["(ruby)\\s+([^\\s]+)\\.rb\\b", 2] - - ["(go)\\s+(generate|run)\\s+([^\\s]+)", 3] + - ["(go)\\s+(generate|run)(?:\\s+-[^\\s]+)*\\s+([^\\s]+)", 3] - ["(dotnet)\\s+([^\\s]+)\\.csproj\\b", 2] From 589e1e5c197483f4ff8d31d70c12dda8a016c2d3 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 15 Apr 2026 16:27:06 -0400 Subject: [PATCH 4/5] Update actions/ql/lib/ext/config/poisonable_steps.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- actions/ql/lib/ext/config/poisonable_steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/ql/lib/ext/config/poisonable_steps.yml b/actions/ql/lib/ext/config/poisonable_steps.yml index cf7f71dccc94..17b1408fa7c3 100644 --- a/actions/ql/lib/ext/config/poisonable_steps.yml +++ b/actions/ql/lib/ext/config/poisonable_steps.yml @@ -70,7 +70,7 @@ extensions: - ["(source|sh|bash|zsh|fish)\\s+([^\\s]+)\\b", 2] - ["(node)\\s+([^\\s]+)(\\.js|\\.ts)\\b", 2] - ["(python[\\d\\.]*)\\s+([^\\s]+)\\.py\\b", 2] - - ["(python[\\d\\.]*)\\s+([\\-m]+)\\s+(\\w+)\\b", 2] # eg: pythonX -m anything(dir or file) + - ["(python[\\d\\.]*)\\s+-m\\s+([A-Za-z_][\\w\\.]*)\\b", 2] # eg: pythonX -m anything(dir or file) - ["(ruby)\\s+([^\\s]+)\\.rb\\b", 2] - ["(go)\\s+(generate|run)(?:\\s+-[^\\s]+)*\\s+([^\\s]+)", 3] - ["(dotnet)\\s+([^\\s]+)\\.csproj\\b", 2] From ed4e2bc5b93ae618ec07dff2c4ba0aa5f853555d Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 15 Apr 2026 16:29:57 -0400 Subject: [PATCH 5/5] Improve formatting helpfiles --- actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.md | 2 +- actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.md | 2 +- actions/ql/src/Security/CWE-829/UntrustedCheckoutMedium.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.md b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.md index 246e302e85b8..a4fceb1f8da3 100644 --- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.md +++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.md @@ -133,4 +133,4 @@ jobs: ## References - GitHub Security Lab Research: [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/). -- Living Off the Pipeline: [LOTP](https://boostsecurityio.github.io/lotp/). \ No newline at end of file +- Living Off the Pipeline: [LOTP](https://boostsecurityio.github.io/lotp/). diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.md b/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.md index f412421b7f1d..a4fceb1f8da3 100644 --- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.md +++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutHigh.md @@ -133,4 +133,4 @@ jobs: ## References - GitHub Security Lab Research: [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/). -- Living Off the Pipeline: [LOTP](https://boostsecurityio.github.io/lotp/). \ No newline at end of file +- Living Off the Pipeline: [LOTP](https://boostsecurityio.github.io/lotp/). diff --git a/actions/ql/src/Security/CWE-829/UntrustedCheckoutMedium.md b/actions/ql/src/Security/CWE-829/UntrustedCheckoutMedium.md index 246e302e85b8..a4fceb1f8da3 100644 --- a/actions/ql/src/Security/CWE-829/UntrustedCheckoutMedium.md +++ b/actions/ql/src/Security/CWE-829/UntrustedCheckoutMedium.md @@ -133,4 +133,4 @@ jobs: ## References - GitHub Security Lab Research: [Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/). -- Living Off the Pipeline: [LOTP](https://boostsecurityio.github.io/lotp/). \ No newline at end of file +- Living Off the Pipeline: [LOTP](https://boostsecurityio.github.io/lotp/).