Skip to content

feat(security): detect GitHub Actions execution integrity risks - #1424

Draft
seonghobae wants to merge 40 commits into
developfrom
codex/detect-runtime-package-integrity
Draft

seonghobae wants to merge 40 commits into
developfrom
codex/detect-runtime-package-integrity

Conversation

@seonghobae

@seonghobae seonghobae commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Goal

Retain two high-confidence GitHub Actions supply-chain defect families as executable appguardrail regressions on the existing canonical detector writer:

  1. a versioned registry package admitted for runtime auto-install through npx / npm exec;
  2. a privileged pull_request_target job that materializes mutable PR-head content and then executes code from that tree.

Exact scope

Exact head: a47de52c1f6d0f49e44a72e35b713b1738bf10fa
Exact tree: d73233defc3a386f5e64a2327da75f501f7e1f82

Effective diff is detector/test/documentation only:

  • scanner/cli/appguardrail.py
  • scanner/rules/github_actions.yml
  • tests/test_github_actions_runtime_package_integrity.py
  • tests/test_github_actions_writer_rules.py
  • ARCHITECTURE.md
  • docs/TRACEABILITY.md
  • CHANGELOG.md

No protected workflow, manifest, lockfile, bootstrap, gate, dependency, or finding suppression is changed.

Root causes and causal boundaries

Runtime registry package integrity

Version pinning constrains package selection but does not authenticate registry bytes. The rule requires one step to bind a versioned registry identity to *_PACKAGE and use that exact variable in a supported npx / npm exec package-selector position with -y / --yes. It does not claim a download or compromise occurred.

Negative boundaries include lock-installed local binaries, unbound/local names, local tarballs, cross-step values, ordinary arguments, variable-prefix collisions, comments, printed examples, quoted heredocs, and non-workflow YAML.

Privileged PR-head execution

Retained corpus: appguardrail issue #132. Canonical prevention repair: ContextualWisdomLab/.github PR #635.

The job-local analyzer requires the complete causal chain:

  • pull_request_target;
  • explicit write/OIDC authority or a repository secret in the same job;
  • action-owned with.ref checkout, direct shell checkout/switch, or PR-head fetch followed by FETCH_HEAD worktree creation and entry, using equivalent dot/bracket expressions or a one-hop workflow/job/same-step env binding;
  • subsequent local action, script, test, build, or workspace analyzer execution from the selected tree.

A fetch alone is not materialization. Metadata-only handling, ordinary pull_request, trusted-base checkout, inert output, authority isolated in another job, unrelated checkout inputs, cross-step aliases, shell comments, and conservatively proven event guards whose every disjunct excludes PR-target execution remain negative. Top-level field order, trigger forms, single-line/multiline flow mappings, trailing comments, and dot/bracket context syntax are syntax-equivalent. Non-overwriting fetch modes preserve FETCH_HEAD; later trusted checkout/switch or overwriting fetch invalidates prior PR-tree provenance; normalized worktree execution paths bind only executable/script locations, not arbitrary arguments.

The bounded analyzer does not claim reusable/composite internals, cross-job artifacts, API-downloaded archives, cross-step or multi-hop aliases, arbitrary boolean theorem proving, container entrypoints, or third-party actions that fetch contributor content internally.

RED / GREEN evidence

RED:

  • the protected runtime-package incident produced the expected HIGH finding;
  • the exact issue 예비 보안 점검 결과 — ContextualWisdomLab/appguardrail #132 env-alias/fetch/worktree/entry/CodeGraph shape initially produced no PR-target finding;
  • seven independent review rounds reproduced twenty-eight Important boundary defects before repair, covering guard reachability, expression syntax, YAML scope/order/ownership, shell command and comment binding, tree selection, and execution-directory causality.

GREEN at exact tree d73233defc3a386f5e64a2327da75f501f7e1f82:

  • full suite: 1,187 passed;
  • focused GitHub Actions regression modules: 116 passed;
  • python3.12 -m compileall -q scanner/cli/appguardrail.py tests/test_github_actions_writer_rules.py: pass;
  • git diff --check: pass;
  • uploaded Git blobs and tree are byte-identical to the tested local tree.

Independent review repair

  • 4ddc75bbe25c024fd2b76be91d08163747906e96: repaired dispatch guards, exact 예비 보안 점검 결과 — ContextualWisdomLab/appguardrail #132 shape, inert YAML authority, and equivalent trigger/ordering syntax.
  • 40ad888e36287bc44a7dff4ebb0295992a11edb6: repaired compound/block guards, env scope, checkout field binding, shell segment binding, and bracket secret syntax.
  • 96fb137b2ae4d81058e81f8fa6ae302a5b20c9ce: repaired boolean negation/disjunction, bracket PR-head expressions, post-jobs top-level fields, same-step aliases, flow with.ref, mapping ownership, fetch-only/comment false positives, and worktree-entry causality.
  • 0d45c3b16335483de2e0348b4a5f88ed1843324c: repaired boolean comparison inversion, block/flow env parity, worktree cd/pushd/working-directory/absolute-path execution binding, trusted scalar false positives, and latest-fetch ownership of FETCH_HEAD.
  • a850c1a694d584a95d122b8c2c04ed16445ece9c: repaired unrelated boolean-negation handling, multiline flow mappings, non-overwriting fetch semantics, later trusted tree-selection invalidation, and normalized executable/worktree-path binding.
  • 9dfcd9adf56cfc49ca562d2ba6223cae125cc30c: repaired effect-aware direct git selection, run-block checkout data isolation, interpreter-option worktree execution, and bundled append-fetch semantics.
  • a47de52c1f6d0f49e44a72e35b713b1738bf10fa: retained current-HEAD checkout/detach/force provenance and interpreter options that consume separate arguments; focused independent re-verification found the six reported reproductions GREEN and no new Critical.

All reproductions remain regression fixtures. The final focused current-tree independent re-verification found the reported boundary reproductions GREEN with no new Critical; hosted exact-head Checks remain required.

Canonical owner prerequisites

For runtime package integrity, central PR ContextualWisdomLab/.github#532 repaired the owner's internal workflow but did not release a reusable immutable consumer contract. The release gap remains tracked in ContextualWisdomLab/.github#2610.

For privileged PR-head execution, the owner repair is already merged in .github#635; this PR retains the causal pattern in appguardrail so fixed incidents remain regression corpus rather than disappearing from detection history.

Status

Draft / Proposed. The new exact head invalidates prior hosted evidence. Merge remains held until exact-head hosted checks materialize and current-head review/thread evidence is terminal. No gate is bypassed or weakened.

@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Contributor Author

Exact-head validation and hosted gate RCA

  • Exact head: 3a79d830a495bb87a7affedb9c09eb5506425786
  • Local exact-tree verification: 1,101/1,101 passed
  • Focused runtime-package corpus: 35/35 passed
  • Isolated lock install: npm ci --ignore-scripts --omit=dev --no-audit --no-fund succeeded
  • Locked local binary: CodeGraph 0.9.9
  • Repaired production workflow: new rule finding count 0
  • Remote tree is byte-identical to the locally verified tree.

Hosted exact-head runs are terminal FAILURE before execution:

Workflow run Jobs
Tests 37891980276 113694713853, 113694714071
Security Process 37891980403 113694714298, 113694714516
Scan path 37891980329 113694713715
Pinned HTTPS 37891980309 113694713686
Retention 37891980320 113694714035
OpenSSF 37891980241 113694714177

All eight jobs expose steps=null and logs_url=null. No checkout, npm install, scanner, test, or security step executed. This is runner/admission evidence, not a source verdict; it matches the preserved central RCA class in ContextualWisdomLab/.github#2356.

Current-head reviews: 0. Review threads: 0. Keep Draft / Proposed / merge HOLD. No blind rerun, wake commit, inherited Check/approval, suppression, gate weakening, Force Push, destructive rebase, merge, or release.

Copy link
Copy Markdown
Contributor Author

Independent exact-head review findings accepted

Read-only independent review of exact 3a79d830a495bb87a7affedb9c09eb5506425786 found Critical 0 / Important 4. All four findings are accepted:

  1. The PR checkout's lockfile is not a trusted provenance root; copying it into runner.temp does not preserve central owner PR [security-failure] ContextualWisdomLab/naruon: Required OpenCode Review ContextualWisdomLab/naruon#1203@27cb947372e2938cde0aa8f0baec547228d0eecc #532's protected-source boundary.
  2. The initial line regex overclaimed registry download/integrity absence and reported locked-local or local-tarball npx cases.
  3. Common option/prefix forms were outside the declared FN boundary.
  4. The regression asserted only the JS wrapper integrity, not every selected native platform payload.

Repair direction before any merge:

  • remove the consumer-local workflow/package-lock workaround from this PR;
  • keep the actual protected workflow as a positive retained incident instead of claiming it fixed;
  • narrow the HIGH detector to the high-confidence causal pair: a versioned registry package bound in a *_PACKAGE workflow environment entry and then executed through npx -y/--yes or npm exec -y/--yes;
  • add explicit negative regressions for lock-installed local names, local tarballs, and documentation heredocs;
  • document direct literal packages, prefixes/option orderings, other package managers, chaining, and indirection as unimplemented until a structural workflow/shell analyzer can support them without HIGH false positives;
  • retain feat(security): detect GitHub Actions execution integrity risks #1424 as Draft/Proposed and record the unresolved canonical-owner reusable/immutable consumption prerequisite rather than copying central source.

No review was dismissed and no gate was weakened. This comment records the rationale before source repair.

Copy link
Copy Markdown
Contributor Author

Current-head review repair — exact evidence

The independent read-only review of predecessor head 3a79d830a495bb87a7affedb9c09eb5506425786 reported 0 Critical / 4 Important findings:

  1. PR-owned lock/bootstrap material was not an independent trust boundary.
  2. The broad line regex overclaimed registry execution and admitted false positives.
  3. The claimed coverage did not match common wrapper/option forms.
  4. The lock regression authenticated the JS wrapper but not the native platform package.

All four findings were accepted. The branch was repaired through ordinary additive commits; no force-push or destructive rebase was used.

Current exact head: 1a923ea9659462f95e6e8d333acb4186f6e6e80c
Current exact tree: 9143b1291b1cdb455bc6f48cda54e161d0faa011

Effective diff now contains five detector/test/docs files only. It has no workflow, package manifest, lockfile, bootstrap, gate, or dependency change. The local tested tree and remote exact-head tree are byte-identical.

Verification:

  • full suite: 1,103 passed in 22.57s
  • focused detector module: 37 passed
  • git diff --check: pass
  • protected workflow/bootstrap effective diff: empty
  • expected corpus incident: protected security-process.yml produces exactly one HIGH finding

The remaining consumer repair is correctly held at the canonical owner boundary: ContextualWisdomLab/.github#2610. This PR remains Draft/Proposed until current-head hosted checks and review evidence are terminal.

Copy link
Copy Markdown
Contributor Author

Hosted exact-head RCA

Current head 1a923ea9659462f95e6e8d333acb4186f6e6e80c materialized six pull-request workflow runs:

  • 37893584859 — Scan path context coverage
  • 37893584753 — Retention Audit Coverage
  • 37893584925 — OpenSSF Evidence Coverage
  • 37893584845 — Tests
  • 37893584733 — Pinned HTTPS Coverage
  • 37893584781 — Security Process

All eight jobs reached terminal failure before any workflow step materialized: every job reports steps=null. There is therefore no checkout, dependency install, test, detector, or changed-source log to repair or rerun. This matches the continuing hosted pre-runner/platform failure class and is not evidence of a source regression.

The exact local/remote-identical tree remains GREEN at 1,103 tests and git diff --check. The PR stays Draft and merge is held; no failed status is suppressed and no predecessor check is transferred. Owner/platform RCA continues independently while safe detector and canonical-owner lanes proceed.

Copy link
Copy Markdown
Contributor Author

Third-review repair — structural shell state

Review of predecessor 9c193e2bdb3e8040afada617d2f556ed3e1e1b89 found 0 Critical / 1 Important: regex block-scalar handling could be bypassed by a blank line, stopped after a quoted heredoc, and promoted an unexecuted unquoted heredoc body to HIGH.

The finding is accepted. The proximity regex has been replaced by a deterministic step/run analyzer.

Current exact head: a177c5d00bcc5dc97c8c698e2afa6ed5ad8088e2
Current exact tree: 857042be74873d4e5eaa6dd5a1027b53754c7e06

The analyzer now:

  • parses one step's env → immediately following run boundary;
  • preserves blank block-scalar lines;
  • tracks quoted and unquoted heredoc delimiters and resumes scanning after closure;
  • ignores heredoc body text by default;
  • recognizes heredoc package execution only when an unquoted body is redirected to a target and a direct chmod later gives that exact target execute bits;
  • rejects echo-only/non-executable chmod evidence;
  • preserves exact variable and package-selector boundaries.

New regression fixtures cover blank-line bypass, a real command after a quoted heredoc, unexecuted unquoted heredoc text, executable wrapper materialization, echo-only chmod, and non-executable mode.

Byte-identical local/remote verification:

  • full suite: 1,113 passed
  • GitHub Actions focused: 67 passed
  • git diff --check: pass
  • effective diff: six analyzer/rule/test/docs files
  • protected workflow/manifest/lock/bootstrap diff: empty
  • protected incident: exactly one expected HIGH finding

Draft/merge HOLD remains pending fresh exact-head hosted and independent final review evidence.

Copy link
Copy Markdown
Contributor Author

Current exact-head hosted RCA after analyzer repair

Head a177c5d00bcc5dc97c8c698e2afa6ed5ad8088e2 materialized six runs: 37895295982, 37895296008, 37895296011, 37895296058, 37895296096, and 37895296154.

All eight jobs are terminal failure with steps=null. No checkout, analyzer, test, or security step ran; no source log exists and a source-cause rerun is not justified. The exact byte-identical tree remains locally GREEN at 1,113 full / 67 focused tests and clean diff check.

Draft/merge HOLD remains; no failure is suppressed and no predecessor status is transferred.

Copy link
Copy Markdown
Contributor Author

Compact step syntax repair — exact head

Final review of predecessor a177c5d00bcc5dc97c8c698e2afa6ed5ad8088e2 found 0 Critical / 1 Important: valid compact - env: step syntax bypassed the analyzer. The same-indent comment boundary was also retained as a regression.

The finding is accepted and repaired without force-push.

Current exact head: a0fab92ab9f854e641b2f7de46a3e39fea2562e3
Current exact tree: 0c7c7f5b0705ca9d5c30625ac0ebb5591a2c5513

The analyzer computes logical field indentation from either expanded env: or compact - env: syntax and skips YAML comments while locating the same-step run field. Both RED fixtures are GREEN.

Exact byte-identical verification:

  • full suite: 1,115 passed
  • GitHub Actions focused: 69 passed
  • git diff --check: pass
  • effective diff remains six analyzer/rule/test/docs files
  • protected workflow/package/lock/bootstrap diff: empty
  • protected incident: exactly one expected HIGH

Draft/merge HOLD remains pending fresh hosted and final current-head review evidence.

Copy link
Copy Markdown
Contributor Author

Current exact-head hosted RCA after compact-syntax repair

Head a0fab92ab9f854e641b2f7de46a3e39fea2562e3 materialized runs 37895922870, 37895922921, 37895922930, 37895922969, 37895923010, and 37895923182.

All eight jobs are terminal failure with steps=null. No checkout, test, analyzer, or security command executed; no source-cause rerun is justified. Exact local/remote tree verification remains GREEN at 1,115 full / 69 focused tests and clean diff check.

Draft/merge HOLD remains; no status transfer or suppression is used.

Copy link
Copy Markdown
Contributor Author

Independent final read-only review

Current exact head a0fab92ab9f854e641b2f7de46a3e39fea2562e3, tree 0c7c7f5b0705ca9d5c30625ac0ebb5591a2c5513: Critical 0 / Important 0.

The independent agent re-ran the compact - env:, same-indent comment, causal binding, block-scalar blank line, quoted-heredoc continuation, unexecuted heredoc, echo-only chmod, non-executable mode, exact-target executable wrapper, and protected incident cases. Focused module was 24/24 and exact archive full suite 1,115/1,115. Docs match the bounded analyzer and the effective diff remains the same six files with no workflow/package-lock changes.

This is read-only engineering review evidence, not a GitHub approval or merge authority. Connector review submissions and inline threads are re-fetched separately; Draft/merge HOLD remains because hosted jobs did not execute steps.

@seonghobae seonghobae changed the title feat(security): detect unlocked runtime npm execution feat(security): detect GitHub Actions execution integrity risks Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Exact-head update (2026-10-09)

Hosted exact-head evidence is not executable yet: all eight jobs across runs 37898609104, 37898609109, 37898609137, 37898609120, 37898609135, and 37898609071 terminated failure with steps=null and logs_url=null. This is recorded as central runner/RCA evidence in ContextualWisdomLab/.github#2356. The PR remains Draft; no merge, suppression, or gate bypass is attempted.

Copy link
Copy Markdown
Contributor Author

Exact-head verification refresh

  • hosted head: 96fb137b2ae4d81058e81f8fa6ae302a5b20c9ce
  • tested tree: cf98f891634b767b43f06b5f7a977b75ca9c2246
  • source blob: 3afcf009621123abd4d5b1b0308818ad4e34fdb2
  • regression blob: c7e49af7dc81a8842ffbccad0fbd71752ca0e772
  • focused GitHub Actions regressions: 67/67
  • full repository suite: 1,138/1,138
  • compileall and git diff --check: pass

This additive repair binds checkout evidence to ref, shell aliases to the same Git command segment, env aliases to workflow/job scope, recognizes compound/block exclusion guards, and accepts bracket secret syntax. Independent current-tree review and exact-head hosted Checks are pending; the PR remains Draft and is not merge-eligible.

Copy link
Copy Markdown
Contributor Author

Exact-head hosted Checks RCA for 96fb137b2ae4d81058e81f8fa6ae302a5b20c9ce

Six workflow runs materialized and all failed before step execution evidence was available: 37900798890, 37900798826, 37900798828, 37900799070, 37900798718, and 37900798811. Across eight jobs, GitHub returned steps: null and logs_url: null; no repository assertion or detector failure can be attributed from these records. Central RCA evidence is recorded at ContextualWisdomLab/.github#2356 (comment).

Commit status contexts currently report Devin Review and CodeRabbit success, but there are no GitHub review submissions or inline review threads. These status contexts do not substitute for the terminal hosted workflow evidence or approval required for merge. Draft is retained.

Copy link
Copy Markdown
Contributor Author

Third review-repair exact-head verification

  • hosted head: 0d45c3b16335483de2e0348b4a5f88ed1843324c
  • exact tested tree: 837ee553d751163539fb9b4c24072efa73e110e6
  • analyzer blob: c6a6212f1e0ac610a8a907c9690a11d49648140c
  • writer regression blob: 497518c6d3baa2e5ee27fb94fa01f5beba7b634a
  • focused GitHub Actions regressions: 80/80
  • full repository suite: 1,151/1,151
  • compileall and git diff --check: pass

The additive repair separates fetch from tree selection, requires worktree entry before local execution, binds action checkout only to owned with.ref, supports dot/bracket expressions, same-step aliases, flow mappings, post-jobs top-level fields, and conservative boolean guards. Final independent exact-tree review and hosted Checks are pending; Draft/merge HOLD remains.

Copy link
Copy Markdown
Contributor Author

Fourth review-repair exact-head verification

  • hosted head: 7066131672b78dc81cdd3d61e5eaeccf60edc5f4
  • exact tested tree: 5d833a8858b9332b7608d0a0ad1d553622ba8e1a
  • analyzer blob: 5cd35d02744be9fee9e322a014d6bbb45eab7eea
  • writer regression blob: a06fb6a5c3e38c4b9929ed57b634dc6055a0162e
  • focused GitHub Actions regressions: 89/89
  • full repository suite: 1,160/1,160
  • compileall and git diff --check: pass

The additive repair makes event exclusions require standalone atoms, adds block/flow env parity, binds worktree execution through cd, pushd, exact step working-directory, or absolute paths, rejects later trusted scalar execution, and makes the most recent fetch own FETCH_HEAD. Final independent current-tree review and hosted Checks are pending; Draft/merge HOLD remains.

Copy link
Copy Markdown
Contributor Author

Exact-head verification update

  • PR head: a850c1a694d584a95d122b8c2c04ed16445ece9c
  • tested/uploaded tree: 83c90da2382f7026951549008abd4d9b4b8f48b5
  • changed blobs:
    • ARCHITECTURE.md: 58aa351fee3672f91201837f767681e356bd19c1
    • CHANGELOG.md: 6d1bf1c0363a42d1f9800748d0345b0a262f04fb
    • docs/TRACEABILITY.md: a080ee608a614f269e7c540e915684b8287879b8
    • scanner/cli/appguardrail.py: 68a5c3c8d64934c4bc830ef217dac4b7df47b84b
    • tests/test_github_actions_writer_rules.py: c505323541ece5ac7ad19cf472ab3e47f0177b5f

Fresh local evidence on that exact tree:

  • full suite: 1,170 passed
  • focused GitHub Actions modules: 99 passed
  • writer-rule module: 75 passed
  • python3.12 -m compileall -q scanner tests: pass
  • git diff --check: pass

The fifth independent review round's five Important findings are retained as ten new RED→GREEN fixtures: unrelated guard negation, multiline flow mappings, non-overwriting FETCH_HEAD fetch modes, later trusted tree selection, and normalized worktree executable binding.

Hosted exact-head evidence is not GREEN. Six runs terminated with failure before any step record/log materialized (steps=null, logs_url=null):

  • Security Process 37903426442: jobs 113731067008, 113731067412
  • Scan path context coverage 37903426405: job 113731067366
  • Pinned HTTPS Coverage 37903426571: job 113731067733
  • Tests 37903426592: jobs 113731067652, 113731067918
  • OpenSSF Evidence Coverage 37903426630: job 113731068143
  • Retention Audit Coverage 37903426387: job 113731067467

Commit statuses are Devin Review=success and CodeRabbit=success, but GitHub review submissions and review threads are both empty. PR remains Draft / Proposed and merge is held; no gate is suppressed, bypassed, or weakened.

Copy link
Copy Markdown
Contributor Author

Final exact-head evidence update

  • head: a47de52c1f6d0f49e44a72e35b713b1738bf10fa
  • tested/uploaded tree: d73233defc3a386f5e64a2327da75f501f7e1f82
  • final changed analyzer blob: 82ddd82f2dd5b20d560186d6000ddfb855080a16
  • final writer-regression blob: de2cc93e1550e56f69bdc2be6f9fdde457b879d2

Fresh exact-tree local evidence:

  • full suite: 1,187/1,187 passed
  • focused GitHub Actions modules: 116/116 passed
  • compileall: pass
  • git diff --check: pass
  • final focused independent re-verification: current-HEAD checkout/detach/force variants and argument-consuming Python/Bash options all retain one finding; no new Critical found.

Hosted exact-head evidence remains pre-step failure, not repository GREEN:

  • Security Process 37904591588: jobs 113734884484, 113734884722
  • Tests 37904591464: jobs 113734882528, 113734882685
  • Pinned HTTPS 37904591492: job 113734882684
  • Scan path 37904591580: job 113734884193
  • OpenSSF 37904591490: job 113734883246
  • Retention 37904591592: job 113734883693

Every job has steps=null and logs_url=null. Devin Review and CodeRabbit commit statuses are success; GitHub reviews and threads remain empty. Draft / Proposed / merge HOLD remains.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant