Skip to content

Evidence: security review (T13) ​

Tier 4 (autonomy.tiers), and security.review.humanSignOffMinTier: 4 — so this records the harness's own review against the abuse cases in requirements.md, and the named human security sign-off is still outstanding. It is requested in the pull request's briefing.

Why this work item is a security review at all ​

It widens, for the first time since issue-63, the set of people whose text the-loop will act on. The question is not whether a collaborator can comment — it is whether a collaborator can reach an action.

The abuse cases, and what closes each ​

#Abuse caseVerdictWhere it is closed, and what proves it
A1A commenter grants themselvesclosedDispatcher.handle's named-and-allowlisted-actor re-check runs before any command executes. test_a_collaborators_own_grant_attempt_is_refused, test_a_collaborator_cannot_command_the_daemon
A2A collaborator escalates with the-loop stop / cleanup / executeclosedSame check; and the comment is not forwarded either, so it cannot reach the agent as instruction. test_a_collaborator_cannot_command_the_daemon asserts both halves
A3Injection through the login argumentclosednormalize_login refuses everything but GitHub's login grammar — no sanitising, no partial match. 14 rejection cases in test_anything_that_is_not_a_login_is_refused_not_cleaned_up, plus test_nothing_but_a_login_reaches_the_caller (a path and an argv fragment after the keyword reach nothing). Posting is gh argv, never a shell
A4A grant on one work item reaches anotherclosedpermits answers only about the refs handed to it, and both ingresses hand it the event's own refs. test_membership_is_asked_only_about_the_refs_it_is_given, test_a_grant_reaches_one_work_item_and_no_other, test_a_grant_on_another_work_item_does_not_carry
A5A collaborator satisfies a human gateclosedThe hooks read config.authorizedUsers, which this work item does not touch — asserted directly rather than inherited: test_a_collaborators_comment_does_not_reach_a_human_gate
A6A collaborator's comment spawns a sessionclosed_spawn_refusal returns collaborator-no-spawn, settled rather than retried. test_a_collaborators_comment_cannot_spawn_a_session, test_a_collaborators_comment_never_spawns_a_session; and test_a_collaborator_cannot_arm_a_spawn on the poll path
A7The portable record is edited directly to add a collaboratoraccepted, unchangedIdentical to the control section beside it: a writer who can forge control: {command: start} can already arm the item. The record is tracked and human-readable, so such an edit shows up in a pull-request diff, and index.json is derived on every write. A malformed entry grants nobody (test_a_hand_edited_entry_that_names_no_login_grants_nobody)
A8A revoked collaborator keeps reaching the sessionclosedMembership is read per event, never cached in the session record. test_remove_revokes plus the per-event read at both seams
A9A closed item's roster is reused when it reopensclosedCleared on closure with the control record (test_closing_the_work_item_forgets_its_roster) and by sessions reset (test_reset_forgets_the_collaborator_roster)

Two things a reviewer should look at hardest ​

  1. The spawn seam's condition is deliberately two-part — outside authorizedUsersand granted on one of the event's refs — rather than the one-part "outside authorizedUsers". The one-part form is stronger and was tried first; it changes behaviour for events that can only occur when the router is bypassed (fixtures that drive a dispatcher directly with an empty allow-list), and it is not what R3.2 asks for. The reasoning, and why the inference behind the two-part form is written out instead of relied upon, is in design.md §3 and decision-102 D4. If a third path ever admits a named non-authorized actor, that path must state its own rule.
  2. authorizedUsers still matches exactly; the roster matches case-insensitively. Deliberate and asymmetric: GitHub logins are case-insensitive, so a roster that stored @Dana and failed to recognise dana would be a silent revocation — but widening how the global list compares is a different decision, and not this one.

What is not claimed ​

No penetration testing, no fuzzing of the login grammar beyond the enumerated cases, and no review of GitHub's own permission model — a grant is meaningful only for someone who can already comment on the work item.

Released under the MIT License.