Skip to content

aggregator(alerts): aggregator-wide auth/CSRF posture for mutating routes (#3702 disposition 2) #4980

Open

Description

@dezren39

Disposition 2 of design #3702 Phase 3 (audit task 5613, 2026-11-03). The aggregator has no auth model at all; the throat's mutating routes inherit that. Exact current exposure (all unauthenticated):

  • DELETE /api/push/subscriptions (pm-stack/aggregator/src/server.ts:1627) — anyone who knows an endpoint can unsubscribe it. Endpoints are handed out by the page itself (render.ts data-unsub + the SUBS script constant), so "the endpoint is a secret" is not a boundary.
  • POST /api/alerts/<id>/(ack|close) (server.ts:1665) — anyone can ack/close an incident, including a critical one, which suppresses its escalation. Route is UUID-gated but not authenticated.
  • POST /api/push/test (server.ts:1643) — anyone can fan a push out to every subscription.

The intake route is the only authenticated one (POST /api/alerts, Bearer token via alertsIntakeAuthorized, server.ts:322).

The Phase 3 stance is: no partial auth on one route while the page that supplies the inputs is public — the aggregator-wide model is the decision, and the mitigation until then is the private origin the app is served on. This issue is that decision's implementation: a shared auth (or signed-page/CSRF) posture for the mutating routes, applied consistently, without breaking assets/push-client.js (POST/DELETE only).

Related open question in the design doc: "an aggregator-wide auth model". Filed from #3702 Phase 3 audit.

Activity

  1. added
    kind/securitySecurity issue or security hardening
    priority/normalOrdinary priority (the default)
    effort/mMedium: expected under 1 day of work
    app/aggregatorPackage/app: aggregator (pm-stack in this repo)
    app/pm-stackpm-stack (Pad/Grist) in developing-today/code
    on Nov 3, 2026
  2. added
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    on Nov 3, 2026
  3. developing-today commented on Nov 3, 2026

    @developing-today
    Contributor

    agent-note:v1
    state: reviewed (coverage loop-back)
    Coverage pass 2026-11-03, loop-back review: this issue was re-reviewed (drift / overlap / already-handled / stale / blockers / ordering) so every open issue in the four repos is reviewed and in the system. Verdict: still live; in the system as task 8562 (triage, queued, priority 40) in repo-health-code-pilot. Labels audited and synced. If it is already handled at current main, its triage closes it with evidence; if oversized, the triage files the split; blockers belong on this issue.
    Found via: coverage loop-back 2026-11-03

  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 3, 2026
  5. 8 remaining items

  6. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    • Agent: fleet monitor (repo-fleet-monitor)
    • Session / ID: task 8562 · repo-fleet-monitor run 2026-11-03 20:12 CST
    • Found via: monitor reconciliation
    • Task: Claim evaporated — task 8562 returned to queued and unclaimed in repo-health-code-pilot after the holding run ended without a terminal verb (checkpoint stage: handed_off). Labels reset to the truth: queue/queued + status/needs-triage. The task cap was also raised this run where it had sat dead-in-queue, so it is claimable again.
    • Expectation: next claimant picks up from the checkpoint stage named above.
  7. added
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 4, 2026
  8. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  9. added
    queue/blockedQueue or user escalation state
    status/blockedQueue or user escalation state
    user/escalatedQueue or user escalation state
    and removed
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    on Nov 4, 2026
  10. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    event: blocked/escalated
    task: 8562 (triage, repo-health-code-pilot; worker repo-worker-code; OpenChamber scheduled lane 9aca43b4-5439-4939-9f71-323f5d32521b)
    by: openchamber-scheduled-lane

    Triage at current main: issue #4980 is OPEN with no linked/open PR. pm-stack/aggregator/src/server.ts at main f00a427a069c403c8323ff6585f6ec4e5a9d5a18 shows the security posture: lines 1786-1818 leave subscription POST/DELETE and push-test POST without a shared auth check; lines 1835-1843 leave incident ack/close POST unguarded; only POST /api/alerts uses alertsIntakeAuthorized (Bearer token, lines 1822-1824). The public /alerts page is served at lines 1845+, so a one-route guard could break the page's push client without establishing a consistent boundary. No PR currently references #4980.

    Conflict requiring owner direction: closed design #3702's Phase 3 disposition (comment 6607325239, item 2) explicitly accepted the no-auth/private-origin posture for v1 and names #4980 as the shared posture; this issue's body instead asks for a shared auth or signed-page/CSRF implementation. The request therefore appears to change the already-recorded security/risk decision.

    Scoped path if the decision changes: apply one common guard to subscription POST/DELETE, push-test POST and incident ack/close POST; preserve the existing Bearer intake check; keep assets/push-client.js POST/DELETE working; add tests for rejected unauthenticated mutations and the authorized browser flow. Current route state is not evidence that this stronger posture is implemented.

    Drew decision requested: does #4980 supersede #3702's accepted v1 no-auth/private-origin stance? If yes, choose the boundary (identity/session auth vs signed-page/CSRF) before implementation. This lane did not change code.
    labels: user/escalated + queue/blocked + status/blocked; in-flight queue/status/work labels removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/aggregatorPackage/app: aggregator (pm-stack in this repo)app/pm-stackpm-stack (Pad/Grist) in developing-today/codeeffort/mMedium: expected under 1 day of workkind/securitySecurity issue or security hardeningpriority/normalOrdinary priority (the default)queue/blockedQueue or user escalation statesource/creatorFiled by the new-issue-creator jobstatus/blockedQueue or user escalation statetask/triageQueue packet kind: verify, reproduce, and route this itemuser/escalatedQueue or user escalation state

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions