BUG BOUNTYFIELD MANUAL
Reusable module
Markdown
0 / 6 checkedChecks last until this page reloads.

CI and releases: trace untrusted input into privileged work

Audit workflow events, shell interpolation, untrusted builds, artifact consumers, and release identity as one privilege chain.

Investigation sequence
  1. 01Identify event trust
  2. 02Map executable input
  3. 03Inspect privileges
  4. 04Follow artifacts
  5. 05Validate locally
  6. 06Verify release identity

At each step: retain the control → record the observation → continue only while the next boundary is understood.

Used in these playbooks#

Draw the actual privilege chain#

For every release-capable workflow, record event actor, workflow-file revision, checked-out revision, executable inputs, token permissions, reachable secrets, runner persistence, and final consumer. Distinguish data review from code execution: a checked-out contribution becomes executable through Makefiles, package install hooks, test discovery, plugins, and local actions as well as explicit shell scripts.

Use one row per job. Include reusable workflows and composite actions; apparent isolation at the top-level YAML may disappear inside their implementation. A permissive token setting without a lower-trust entry is a hardening observation, not a completed takeover claim.

Boundary Local evidence to collect Comparison control
Metadata → generated shell Original expression and resulting script Environment variable passed as data
Fork content → privileged build Exact fetched revision and executed file Trusted base revision only
Test artifact → publisher Producer identity, run association, consumed path Artifact from expected trusted build
Build → attestation → release Artifact digest and accepted signer identity Wrong-source artifact rejected

Triage commands and a safe coding pattern#

These examples inspect local files; they have not been run against a target. Grep-style matching deliberately overselects candidates.

rg -n --hidden -g '*.yml' -g '*.yaml' \
  'pull_request_target|workflow_run|issue_comment|permissions:|id-token:' \
  ./repo/.github
rg -n --hidden -g '*.yml' -g '*.yaml' \
  'download-artifact|upload-artifact|cache-mode|head\.sha|npm install|make ' \
  ./repo/.github

Passing untrusted metadata through an environment variable avoids inserting its contents into the generated shell program. Quote it and do not subsequently eval it. This pattern does not solve dangerous argument semantics in downstream tools. GitHub secure use.

- name: Inspect title as data
  env:
    PR_TITLE: ${{ github.event.pull_request.title }}
  run: printf '%s\n' "$PR_TITLE"

Check current protections before declaring a pwn request#

GitHub currently documents fork-ref checkout protection for pull_request_target and read-only default cache access for that event. Inspect action revision, explicit allow-unsafe-pr-checkout, cache-mode, manual fetches, repository policy, and actual execution. The trigger name alone proves neither execution nor writable cache. Controls can differ from older published examples. Current pull_request_target guidance.

Hypothetical trace: an unprivileged test job uploads report.zip; a privileged follow-up selects an artifact by a generic name; an extracted helper is executed before publication. Validate run/repository binding, extraction destination, and consumer behavior in your own fixture with an inert marker and dummy credentials. A successful workflow conclusion does not authenticate every byte it produced. An artifact parsed strictly as data may break the supposed execution chain. GitHub Security Lab workflow analysis.

Follow identity to the shipped artifact#

For a known public artifact, this read-only verification example contacts GitHub. Replace repository, workflow, and commit with expected identities established independently; do not copy identities out of the untrusted artifact and then “verify” against them.

gh attestation verify ./dist/product.tar.gz \
  --repo OWNER/REPO \
  --signer-workflow OWNER/REPO/.github/workflows/release.yml \
  --source-digest EXPECTED_COMMIT \
  --format json > ./evidence/attestation.json

A reusable workflow may be the signer rather than the calling workflow. Verified provenance supports an origin claim; it does not prove the builder was uncompromised or the software is vulnerability-free. GitHub CLI verification.

Trusted publishing reduces long-lived publish-token exposure, but a compromised authorized workflow can still obtain publishing authority. Review environment approval, workflow identity, build separation, and remaining legacy credentials. PyPI trusted publisher security model.

Report and retest gate#

  • A permitted low-trust actor controls the demonstrated input.
  • Exact workflow/action revisions and security defaults are captured.
  • Inert local reproduction reaches the privileged consumer.
  • Real permissions are supported by configuration, not guessed from a trigger.
  • Artifact run binding and signer/source identity are checked.
  • Patched data handling rejects the case while normal releases still work.

Report the reachable capability and its prerequisites. Do not run target publishing steps or use discovered tokens to prove a local workflow hypothesis; maintainers can confirm live permissions through a coordinated reproduction when needed.

For GitLab repositories, also use GitLab pipeline boundaries: parent-project merge-request execution, job-token permissions and runner isolation have distinct semantics.

Vulnerability reverse references#

Nearby shared procedures#

Object, function, and property authorization · Authentication, recovery, federation, and session lifecycle · Trace input into queries, commands, and templates · Server-side fetching and network trust boundaries · Browser execution, cross-origin reads, and forged actions · Uploads, downloads, paths, archives, and XML · Workflow invariants, replay, idempotency, and races · REST, GraphQL, gRPC, WebSocket, and SSE permission parity