#13 Security: runner RPCs can tamper with arbitrary run and step records
closedFrom secscan triage. Severity: MEDIUM. CWE-863.
Source: any valid runner bearer token can authenticate to the runner gRPC service (src/runner-service.lisp:19-27).
Sink: several mutating handlers update caller-supplied IDs without verifying that the authenticated runner owns the task or is in scope for the target repo. handle-append-task-log ignores ctx entirely (src/runner-service.lisp:105-111). handle-update-task-status authenticates the runner but updates run-id / job-id without ownership checks (src/runner-service.lisp:113-141). handle-update-step-status and handle-append-step-log ignore ctx and update arbitrary step-ids (src/runner-service.lisp:215-232). The model layer updates are ID-only (src/model.lisp:570-588, src/model.lisp:861-879, src/model.lisp:977-995, src/model.lisp:997-1002).
Impact: a repo-scoped or user-scoped runner token can mark unrelated automation runs/workflow jobs successful or failed, forge logs, or corrupt another repo's build evidence by guessing/enumerating IDs.
Exploit sketch: with any valid runner auth token, call UpdateTaskStatus using another run id and status=success, or call UpdateStepStatus / AppendStepLog with another step id. The current code does not require the task to be assigned to that runner.
Recommendation: require runner auth on every mutating RPC, and make updates conditional on runner_id plus scope ownership. For steps, join through job -> workflow run -> repo and verify the authenticated runner is assigned to that job before accepting status/log updates.
Note: triage candidate requiring human review; source verified, PoC not executed.
Fixed in commit b4bb966 (Fix runner and review authorization checks). Runner mutating RPCs now require authenticated runner metadata and only update logs/status for runs, jobs, or steps assigned to that runner.