Repository navigation
fix(api): never trust the CoinPay email on Sign in with CoinPay - #171
Merged
Merged
Conversation
CoinPay does not verify email addresses, so its userinfo email proves nothing. The callback stored it in the unique users.email column and set email_verified from `info.email_verified ?? !!info.email`, which treated an omitted flag as verified. A CoinPay account could squat an address before its owner signed up (their signup then 409'd), and a CoinPay login whose email matched an existing account failed with a unique-violation 500. Now the account is resolved by sub only; a new CoinPay account never takes an email another account holds and is never marked verified; a password signup can reclaim an address held only by an unverified, password-less CoinPay account. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
ThreatCrush Security Scan50 finding(s) HIGH/CRITICAL: 2 | MEDIUM: 27 | LOW: 21
Snippets are redacted; ThreatCrush never prints matched credential material. |
sh1pt-actions-fleet Bot
added a commit
that referenced
this pull request
Oct 29, 2026
… in settings (#173) The CoinPay client (cp_56ff186e…) never sent PKCE, so it had to stay in CoinPay's legacy mode. Now, via @profullstack/coinpay-onboard/oauth 0.3.1: - start: PKCE S256 + state + nonce, kept in one httpOnly cookie scoped to /api/auth/coinpay; scopes exactly openid profile email (the old request asked for did + wallet:read, which the client was never registered for, so CoinPay dropped them; sign-in only uses the sub). - callback: constant-time state check; code exchange with the verifier and the client secret (client_secret_post only, not both methods); id_token iss/aud/exp/nonce checked and the userinfo sub matched. - Sub binding unchanged (#171): a CoinPay login never claims an account by email. - New: Settings -> Connect CoinPay (signed in only) / Disconnect (refused when the account has no password). /api/auth/me reports both. Co-authored-by: Anthony Ettinger <anthony@profullstack.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CoinPay never verifies email addresses (userinfo reports email_verified=false), so the email it hands back proves nothing.
Before: the CoinPay callback stored that email in the unique
users.emailcolumn. It also setemail_verified = info.email_verified ?? !!info.email, which counts an omitted flag as verified. Account resolution was already bysub, so there was no takeover. But:After (
services/api/src/coinpay-login.ts):subis the only one a CoinPay login reaches.Tests:
coinpay-login.test.tscovers victim-email login, another sub, verified-flag handling and the unique race.🤖 Generated with Claude Code