Skip to content

security: hybrid gate trusts self-authored Gate-Passed text #66

Description

@forkwright

Finding

The fleet hybrid gate treats a commit-message line beginning Gate-Passed: as a complete gate attestation. The PR author controls that text. No receipt, signature, workflow run, subject tree, policy digest, or verifier identity is checked before the required full build is skipped.

Live evidence

Thumos PR #953 reached review with tip 3f2f1aba29e5040f5e9dc3d79dd5fc5f6fbcb3cc. Its commit body contained:

Gate-Passed: kanon 0.1.0

The PR body truthfully recorded that only kanon gate --tier=nobuild --paths docs/convergence.toml had run and that no full gate passed. Current kanon gate --help explicitly says the nobuild tier never emits the trailer. Independent review caught the contradiction and the PR was closed without merge or history rewrite.

The shared workflow at .github/workflows/hybrid-gate.yml makes the bypass mechanical:

  • check-trailer reads only the PR tip commit body.
  • grep -q "^Gate-Passed:" sets found=true for arbitrary author-controlled text.
  • full-gate-build runs only when found != 'true' on a PR.
  • No later aggregate step establishes that an authorized gate produced the line.

Therefore any contributor who can author a commit message can take the trailer fast path without running the gate. This is the same trust-shape that .github#18 fixed for spoofable release branch names, now on the ordinary PR path.

Why this matters

The required check reports a green gate based on an artifact certifying itself. Other repository workflows may happen to compile some callers, but the fleet-wide required gate contract itself is bypassed, and a caller that relies on it has no independent evidence.

Desired correction

  • Treat the text trailer as a display hint only, never sufficient authorization.
  • Validate a trusted receipt bound to the exact subject tree or commit, exact policy/ruleset digest, completed stages, and verifier identity; or run full-gate-build unconditionally until that receipt exists.
  • Fail closed when a trailer exists without a matching receipt.
  • Add an adversarial fixture whose only apparent attestation is a hand-authored Gate-Passed: line and prove it takes the full-build path. Include a broken build/test in that fixture so a vacuous green cannot satisfy the test.
  • Preserve the default-branch rule that always rebuilds after merge.

Broader design owners: forkwright/kanon#3427 (attestation spine) and forkwright/kanon#3677 (tree identity versus commit metadata).

Done when

An arbitrary contributor-authored trailer cannot skip any required build, while a genuine exact-subject receipt can be independently verified and rejected if its subject, policy, stages, or signer differ.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions