Skip to content

fix(portal): canonicalize nullifier_hash in OIDC authorize (H1 #3896406) - #2162

Open
Gr1dlock wants to merge 2 commits into
mainfrom
Gr1dlock/h1-triage
Open

fix(portal): canonicalize nullifier_hash in OIDC authorize (H1 #3896406)#2162
Gr1dlock wants to merge 2 commits into
mainfrom
Gr1dlock/h1-triage

Conversation

@Gr1dlock

Copy link
Copy Markdown
Contributor

PR Type

  • Regular Task
  • Bug Fix
  • QA Tests

Description

POST /api/v1/oidc/authorize passed the raw, client-supplied nullifier_hash into the nullifier lookup, the nullifier insert, the OIDC auth code, and the id_token sub/email, while verifyProof normalizes the same value internally (decodeToHexString) before verification — so case / 0x-prefix / leading-zero re-encodings of one nullifier all passed proof verification but produced byte-distinct downstream identities, letting a single orb-verified human mint multiple stable OIDC subjects for the same app and create sibling rows in public.nullifier (RP-side Sybil). This PR canonicalizes the nullifier with the existing canonicalizeNullifierHash helper immediately after verifyProof succeeds and uses the canonical value for every identity-forming sink, exactly as the v2/verify handler already does. As a side effect it also closes a concurrency race: two re-encodings submitted with different proofs now collide on the byte-exact unique_nullifier_hash constraint instead of inserting sibling rows. The change is safe for existing data because canonicalizeNullifierHash is idempotent on the standard 0x+64-hex form IDKit emits and already stores. Fixes HackerOne #3896406.

Checklist

  • I have self-reviewed this PR.
  • I have left comments in the code for clarity.
  • I have added necessary unit tests.
  • I have updated the documentation as needed.

🤖 Generated with Claude Code

POST /api/v1/oidc/authorize used the raw nullifier_hash for the nullifier lookup, insert, OIDC auth code, and id_token sub/email, while verifyProof normalizes the same value internally before verification. Case/prefix/leading-zero re-encodings therefore passed proof verification but produced distinct downstream identities, letting one verified human mint multiple stable OIDC subjects and create sibling nullifier rows (RP-side Sybil). Now canonicalizes with canonicalizeNullifierHash right after verifyProof succeeds and uses the canonical value for every identity-forming sink, mirroring the v2/verify handler. Fixes HackerOne #3896406.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Gr1dlock
Gr1dlock requested a review from bin-umar as a code owner July 28, 2026 14:31
@Gr1dlock

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: a91cbc0c77

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

The integration suite stubbed the entire @/api/helpers/verify module with only verifyProof, so the handler's new canonicalizeNullifierHash call resolved to undefined and threw a 500 (Integration Tests CI failure). Spread the real module and mock only verifyProof (the sequencer I/O call) so pure helpers stay real and future exports don't break this again.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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