Severity
P2 / medium cross-job integrity
Review baseline
0bd0e314696e520aa47620cbe8f008d010e01e57
Summary
Some Results/Twirp handlers correctly bind the caller's Actions.Results:{plan}:{job} token to the exact plan/job in the request, but several mutation handlers only rely on the outer generic Results-token check or trust body identifiers directly.
Examples include workflow step updates and log/summary metadata creation. These handlers can accept plan/job/step identifiers without proving that they belong to the token's job.
Why this matters
The signed blob URL minting handlers already use results_token_binds_job(...), demonstrating the intended capability model. The same binding should be enforced for all Results mutations.
Impact
If a job learns another job's backend identifiers, it may be able to alter that job's displayed step state, log metadata, or summary metadata. In a multi-tenant deployment this becomes a cross-job integrity boundary.
Recommended remediation
- Have the Results auth extractor parse and return a typed
JobRuntimeIdentity { plan_id, job_id }.
- Require that identity in every Results mutation handler.
- Reject any request body/path whose workflow plan/job ids differ from the authenticated identity.
- Resolve step ids through the authenticated job rather than treating them as globally writable identifiers.
- Add negative tests where job A attempts every Results mutation using job B's ids.
Acceptance criteria
- Every Results mutation is bound to the exact authenticated plan/job.
- Job A cannot update steps, summaries or log metadata for job B.
- Signed URL minting and metadata/status mutation use the same typed identity model.
- Tests cover both JSON and Twirp/protobuf route variants where applicable.
Severity
P2 / medium cross-job integrity
Review baseline
0bd0e314696e520aa47620cbe8f008d010e01e57Summary
Some Results/Twirp handlers correctly bind the caller's
Actions.Results:{plan}:{job}token to the exact plan/job in the request, but several mutation handlers only rely on the outer generic Results-token check or trust body identifiers directly.Examples include workflow step updates and log/summary metadata creation. These handlers can accept plan/job/step identifiers without proving that they belong to the token's job.
Why this matters
The signed blob URL minting handlers already use
results_token_binds_job(...), demonstrating the intended capability model. The same binding should be enforced for all Results mutations.Impact
If a job learns another job's backend identifiers, it may be able to alter that job's displayed step state, log metadata, or summary metadata. In a multi-tenant deployment this becomes a cross-job integrity boundary.
Recommended remediation
JobRuntimeIdentity { plan_id, job_id }.Acceptance criteria