Skip to content

Signup: /signup/payment accepts arbitrary ?email= — attacker can attach Stripe subscription to victim #294

@rubin110

Description

@rubin110

Discovered during ad-hoc testing on PR #284. Full context in .claude/notes/2026-05-20-signup-flow-adhoc-findings.md — Finding 4.

GET /signup/payment?email=victim@example.com is unauthenticated and prefills the Stripe pricing-table's customer-email with whatever's in the URL. No session check, no CSRF (it's a GET), no signup-state check.

Implications

An attacker can craft a link to /signup/payment?email=victim@example.com and pay via their own card. Stripe's customer_email gets set to victim@example.com. When ST2DH receives the webhook, it looks up the DH member by that email and writes stripe_subscription_id + stripe_product_id into the victim's member row.

Net effect: an attacker can attach their Stripe subscription (and any future events tied to it) to a victim's PS1 record, with the victim having no knowledge.

Whether this leads to a further escalation depends on ST2DH's subsequent webhook handling, but the linkage primitive is there.

Suggested approach (needs design)

Three rough options — design conversation required:

  1. Signed token: /signup/payment accepts a short-lived signed token (issued by /signup/submit) rather than a raw email. Token bound to the just-created member_id.
  2. Session-bound: drop the ?email= query param entirely; always read session['signup_email'] set by /signup/submit. Means the user has to come from the submit step (back-button still works because of session persistence).
  3. Stripe-side fix: have ST2DH require the Stripe customer's email to match a member who has just submitted signup (via a short-lived nonce in Stripe customer metadata) — more complex.

Option 2 is the smallest change and probably sufficient. Worth discussing.

Context: #283, PR #284

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingsecurity

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions