CI Trust Boundaries: Keep Untrusted Changes Away from Release Authority
Separate contributor-controlled execution from privileged release jobs and protect the artifacts that cross between them.
A pull request is a request to review code. It is not permission for that code to execute with production release authority. CI systems blur this distinction because tests, build scripts, dependency installers, and generated artifacts all look like ordinary engineering work.
My review would begin with a data-flow diagram showing where contributor-controlled bytes can influence a privileged process. The workflow file is only one input. A package install hook, test helper, compiler plugin, or archived build output can cross the same boundary.
Separate the execution domains
I would use three logical stages:
1
untrusted validation -> reviewed source revision -> privileged release build
Untrusted validation gets narrowly scoped read access and disposable execution. It does not receive deployment credentials or a writable checkout token. The release stage rebuilds the reviewed revision in a controlled environment and records the digest it produces.
If a design promotes artifacts from an earlier stage, it needs a strong binding between the reviewed source, trusted builder, and artifact digest. Simply downloading an artifact named release.zip is not such a binding.
Caches also carry bytes across jobs. A privileged build should not consume executable cache content that an untrusted job can overwrite. Partition cache trust domains and prefer immutable inputs with verified integrity. A cache miss is an availability or cost event; poisoned build inputs are a trust failure.
Reduce authority at the release boundary
Short-lived workload credentials reduce the lifetime of stolen credentials, but their issuance policy matters. Restrict the trusted repository, workflow identity, environment, and source context using the capabilities of the CI and identity providers. A short-lived credential issued to attacker-controlled execution is still dangerous.
The release job should accept a structured revision or digest, not arbitrary shell fragments from pull-request titles or labels. A human approval can authorize a release, but it does not sanitize the code that will execute after approval.
SLSA’s verification model is a useful reference for binding artifacts to trusted build expectations. The separation of CI stages described here is an architectural proposal; the exact controls must be checked against the selected CI provider.
Make the secure route the convenient route
I would have release engineering publish one supported workflow with clear extension points. Teams should be able to add tests without obtaining the authority to change credential issuance or bypass artifact verification.
Before rollout, exercise an untrusted change that modifies a build script, attempts to access release secrets, writes a shared cache, and substitutes an artifact. Use benign markers in a disposable environment. The expected evidence is that the change can run its tests but cannot acquire release authority or contaminate the release output.
Leadership matters when teams need exceptions for unusual toolchains. Give them an owner and a supported design review, then feed recurring needs back into the platform. A policy that leaves every team inventing its own privileged workflow multiplies the very trust boundaries it is trying to control.