api passthrough bypasses the forge write guard #784

Closed
opened 2026-10-16 01:00:21 +00:00 by hexajon · 0 comments
Owner

The forge write guard runs on the two first-class send paths only. The raw api passthrough sends its writes through a different path that never calls the guard, so a write through madtea api or madt_api_call reaches the forge with no check.

Reachable today:

  • DELETE /repos/<owner>/<repo>/issues/42 hard-deletes an issue, an omitted and unrecoverable destroy.
  • PUT /repos/<owner>/<repo>/contents/x {"branch":"main"} writes the default branch.
  • POST /repos/<other>/<repo>/contents {...} writes a repo outside the session scope.

Until the passthrough calls the guard, the endpoint-effect matcher is dead code in production and the "every surface" promise of the write-guard design is not met.

Fix:

  • Route every passthrough write through the guard before dispatch. Reads (GET, HEAD, OPTIONS) and pagination stay unguarded.
  • The guard matches on the api-relative path, so normalize an absolute or full-URL target to that path before the check, or the match silently returns no effect and the write is allowed.

Acceptance:

  • A passthrough write to the default branch, an omitted delete, and an out-of-scope content write are each refused.
  • A passthrough read is never refused.
  • A passthrough write sent in absolute mode is guarded too.

Part of the write-guard work (#670). Found while enabling the guard (#660).

The forge write guard runs on the two first-class send paths only. The raw `api` passthrough sends its writes through a different path that never calls the guard, so a write through `madtea api` or `madt_api_call` reaches the forge with no check. Reachable today: - `DELETE /repos/<owner>/<repo>/issues/42` hard-deletes an issue, an omitted and unrecoverable destroy. - `PUT /repos/<owner>/<repo>/contents/x {"branch":"main"}` writes the default branch. - `POST /repos/<other>/<repo>/contents {...}` writes a repo outside the session scope. Until the passthrough calls the guard, the endpoint-effect matcher is dead code in production and the "every surface" promise of the write-guard design is not met. Fix: - Route every passthrough write through the guard before dispatch. Reads (GET, HEAD, OPTIONS) and pagination stay unguarded. - The guard matches on the api-relative path, so normalize an absolute or full-URL target to that path before the check, or the match silently returns no effect and the write is allowed. Acceptance: - A passthrough write to the default branch, an omitted delete, and an out-of-scope content write are each refused. - A passthrough read is never refused. - A passthrough write sent in absolute mode is guarded too. Part of the write-guard work (#670). Found while enabling the guard (#660).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
sixfold-space/madtea#784
No description provided.