Course outline

GitHub Actions / Identity, coordination, and governance / Lesson 16

Privileged events and untrusted source

Separate metadata automation from execution of contributor-controlled code and artifacts.

About 4 min readContent reviewed
On this page

Lesson goals

  • Explain the trust difference between pull_request and pull_request_target.
  • Review workflow_run artifacts and indirect execution paths.

An event changes the trust context

A fork pull request contains code controlled by someone outside the base repository’s trusted writer set. GitHub documents restricted token and secret behavior for that low-trust validation path. pull_request_target uses trusted base-repository workflow context and can have elevated authority subject to effective policies and permissions. It exists for tasks such as metadata handling, not as a shortcut to run fork code with secrets. Review the current event protections and repository settings because defaults and enforcement evolve. An old blog example does not establish the current security boundary.

Checking out code is only the first link

The critical failure occurs when privileged execution consumes contributor-controlled code. That can happen through an explicit test command, package installation hook, build configuration, plugin, or helper script. A checkout itself is not the only possible acquisition path: downloaded artifacts, another repository, and a manually fetched ref can supply the same executable influence. Parcel’s privileged metadata job should inspect approved data without executing the proposal. Do not assume that a harmless-looking command such as build or install runs only code written by the workflow maintainer.

Keep validation and metadata roles distinct

The following conceptual split gives untrusted validation no release authority and keeps privileged metadata handling on trusted implementation. It is a review diagram rather than a working event configuration, and no dangerous checkout pattern is installed. A later promotion path must verify the candidate and its source relationship without executing arbitrary uploaded scripts. Separating files or workflows is useful only when the resulting data and authority boundary is actually enforced; renaming a job does not remove shared host identity or executable cache influence.

text Three execution and authority paths
untrusted proposal -> restricted validation -> reports treated as data
trusted metadata implementation -> narrowly authorized metadata operation
verified candidate -> separate reviewed promotion decision

The paths express intended trust boundaries. Actual event policy, token scope, runner isolation, dependencies, and artifact consumers must be reviewed. No proposal code or metadata API operation is executed.

A previous run does not make its uploads trustworthy

workflow_run can start follow-up automation with a different authority context. The preceding run’s conclusion is evidence about that run, not a blanket endorsement of every uploaded byte. Validate run origin, repository, event, revision, expected artifact selection, and the relationship to the requested decision. Parse reports as constrained data and avoid executing downloaded programs. A contributor can often influence report text or filenames even when tests pass. Also consider archive extraction paths and application-level injection in any privileged consumer.

Require source trust as well as a passing result

The complete local predicate below models three required facts: trusted origin, expected artifact selection, and successful required evidence. It rejects a passing but untrusted source. This is not a GitHub event verifier or a comprehensive artifact policy. Real control-plane facts must come from authenticated platform evidence, not a field inside the uploaded report. The model makes one invariant explicit: an artifact cannot declare itself trustworthy, and success from a lower-trust execution does not automatically authorize a higher-trust operation.

python A privilege-transition policy model
def eligible(trusted_origin, expected_artifact, required_checks):
    return trusted_origin and expected_artifact and required_checks
print(eligible(False, True, True))
print(eligible(True, False, True))
print(eligible(True, True, True))
Expected output
False
False
True

The booleans are declared synthetic observations. No event payload, token, artifact archive, or repository is read. This program cannot establish real source trust.

Common errors and fixes

pull_request_target is selected merely to make private credentials available to tests.

Why it happens
A validation convenience crosses into privileged execution of untrusted code.
How to fix it
Keep fork validation restricted and design a separate trusted operation where required.
Prevent it next time
Review executable influence before granting authority.

A workflow_run follow-up executes a script from an uploaded artifact.

Why it happens
A prior run’s success was treated as trust in contributor-controlled bytes.
How to fix it
Consume constrained verified data and avoid executing untrusted artifacts.
Prevent it next time
Review producer origin, subject relationship, and every consumer.

A built-in checkout protection is assumed to cover all acquisition paths.

Why it happens
Equivalent untrusted content can arrive through fetches, dependencies, or downloads.
How to fix it
Trace all executable inputs rather than one action setting.
Prevent it next time
Treat platform guards as layers within a complete trust review.

Check your understanding

1. A trusted metadata workflow reads a proposal title and posts a label. Must it build the proposal first?

Show worked solution

No. Keep its implementation trusted and process the title as validated data through an appropriately narrow API operation. Building the proposal adds executable influence and is unrelated to the metadata decision. Review the input for injection in its actual consumer.

2. A report says trusted=true and tests passed. Can the privileged follow-up rely on that field?

Show worked solution

No. The report producer can control that claim. Establish origin and revision from authenticated platform evidence, validate report structure, and apply the consumer’s own policy. Treat the report’s business observations separately from its self-declared authority.

Key takeaways

  • Privilege follows the effective event and execution boundary.
  • Trace every route by which untrusted bytes can become code.

Official references