Skip to content

fix(account): gate M1, M2 and M3 with hardening: product pin on the verified DID, a viewer address on every request, fresh device-bound genesis with a notice, no tokens for deleted accounts - #191

Merged
WillCybertron merged 1 commit into
mainfrom
fix/account-gate-mediums
Nov 12, 2026

Conversation

@WillCybertron

Copy link
Copy Markdown
Contributor

Day 6 review gate (docs/mobile/review/GATE-REPORT.md in the meta repo), Account-core part 1 of 3: M1, M2 (key log), M3, the deleted-account lead and three hardening items. Each fix has a test that fails without it.

M1, the product signer pin (rfc9421.ts)

  • The product check read the first keyid anywhere in Signature-Input, while the SDK verifies only sig1. A decoy member naming a product made a did:key signer pass as that product.
  • The pin is now decided on the DID the SDK verified: one of PRODUCT_DIDS, or a staging test product. The regex is gone.
  • A did:web outside the allow list is still 403 unknown_signer.
  • Test: signatures.test.ts "gate M1: a decoy Signature-Input member…" answered 200 before this change and 403 now.

M3, one rate-limit bucket for every caller (http.ts ipOf, account-stack.ts)

  • The fix the report asked for cannot be written as an origin request policy. A function URL origin needs every viewer header except Host. allExcept takes no CloudFront headers, allViewerAndWhitelistCloudFront forwards Host, and a whitelist cannot carry Authorization with caching disabled.
  • So a viewer-request CloudFront Function sets x-oe-viewer-address from event.viewer.ip, overwriting any value a client sends, and the existing policy forwards it.
  • ipOf reads that header and refuses with 503 unavailable without it, instead of counting under 0.0.0.0.
  • Tests: gate.test.ts (no header is 503; two addresses have separate buckets) and a stack test that the function is on the only behavior.
  • Post-deploy check: scripts/account-check.sh posts /v1/installs, which needs the address, and expects 201.

M2, the key log part (keylog.ts; the passkey registration part is Account-web's)

  • Genesis needs a sign-in at most 300 s old, otherwise 401 reauth_required.
  • In production it also needs an app session with a device binding (403 binding_required).
  • The owner is told by push (keylog.genesis) and email.
  • freshSignIn and REAUTH_WINDOW move to http.ts; account deletion uses the same check.
  • Tests: gate.test.ts, three checks, each failing without its line.

Lead: product tokens for a deleted account (sessions.ts)

  • accessToken and rotate refuse an account with deleted_at. That also covers a login code redeemed after deletion and a sign-in that raced it.
  • Test: gate.test.ts, with a session opened after the deletion.

Hardening

  • lambda.ts refuses to start on a STAGE other than production or staging. Before, it ran as staging. Test: the handler rejects with STAGE=prod.
  • The app role reads exactly its named parameters. params.ts lists them, and both lambda.ts and the stack use that list, as the forwarder does. Before, it could read every /openentity/account/* parameter.
  • Stack test: the names match exactly with no wildcard. The policy is 5,919 characters, under IAM's 10,240. The unused PARAM_SUFFIX variable is gone.

Contract: POST /o/{id}/log lists reauth_required and production binding_required for genesis.

Tests: account 184 pass, infra account stack 17 pass. Every guard was checked by removing it. scripts/verify.sh is green in the pre-push hook.

…erified DID, a viewer address on every request, fresh device-bound genesis with a notice, no tokens for deleted accounts, fail-closed stage, named SSM grant
@chatgpt-codex-connector

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ❌ Failed 2026-11-12T09:18:45.318121Z
We couldn’t complete this review. Comment @codex review to try again.
65a7ec3 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@WillCybertron
WillCybertron merged commit c860158 into main Nov 12, 2026
1 check passed
@WillCybertron
WillCybertron deleted the fix/account-gate-mediums branch November 12, 2026 09:24
WillCybertron added a commit that referenced this pull request Nov 12, 2026
WillCybertron added a commit that referenced this pull request Nov 12, 2026
…gn-in for the root passkey, grant resend, decoy parity, method.add bound to its identity, ordered Apple notices (#193)

M7, M2 (sign-in part), the deleted-account login code, email decoy and grant delivery leads, and two hardening items, each with a regression test (docs/mobile/review/GATE-FIXES.md in the meta repo). The browser checks now set the viewer address that every request needs since #191.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant