Repository navigation
fix(auth): harden ClerkUserSyncService against account takeover, username collisions, and invalid inputs (#115) - #171
Merged
VarshithReddy2006 merged 2 commits intoNov 11, 2026
Conversation
VarshithReddy2006
approved these changes
Nov 11, 2026
VarshithReddy2006
left a comment
Owner
There was a problem hiding this comment.
LGTM! Thanks for the thorough security hardening and regression test suite @Subodh-17.
To answer your clarification question: yes, keeping strict 400 EMAIL_REQUIRED / INVALID_EMAIL is the intended contract given User.email is required: true, unique: true in the schema and auth/user flows depend on a real email address.
I pushed a small fix (ae7f245) switching ensureSupportingRecords from Promise.all to Promise.allSettled before rethrowing so concurrent UserSettings/UserProfile creation settles cleanly on partial failure (which fixed the flaky/failing assertion in test #12). Verified ClerkUserSyncService.test.ts (22/22), test:safety (16/16), and backend TypeScript build all pass.
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.
Summary of Changes
This pull request resolves Issue #115 by hardening
ClerkUserSyncServiceacross input validation, username generation, concurrency resilience, and cross-identity account linking.Key architectural improvements include:
verification.status === 'verified'. Missing, null, unverified, or non-verified email metadata strictly fails closed with409 UNVERIFIED_EMAIL_CONFLICT. Furthermore, existing accounts linked to an establishedclerkIdcannot be re-linked to a different Clerk identity (409 CLERK_IDENTITY_CONFLICT).isSchemaValidUsername) with MongooseUserschema constraints ({ minlength: 3, maxlength: 30, trim: true }), preserving valid usernames containing whitespace without triggering silent renames.E11000duplicate key errors gracefully acrossclerkId,email, andusernameunique indexes.UserProfile,UserSettings) with existence guards anduserId_1duplicate key absorption. Interrupted provisioning automatically self-heals on subsequent user logins.MongoServerErrorrethrows with structured, sanitizedAppErrorinstances, preventing internal database connection strings or query details from leaking in API responses.Fixes #115
Acceptance Criteria & Issue #115 Matrix
400 BAD_REQUEST(EMAIL_REQUIRED).user_<hash>); slices handles longer than 30 characters before suffix derivation.E11000duplicate key conflicts with bounded random/numeric suffix retries (max 12).UserProfileandUserSettingsexist; handles race conditions gracefully.Maintainer Clarification Question (Criterion #1: Missing Email)
Important
Maintainer Clarification Requested regarding Missing Email Handling:
Acceptance criterion #1 in Issue #115 states:
"If Clerk payload has no email or empty email_addresses array, sync should succeed without email instead of crashing."
However, the
Userschema inbackend/src/models/user.model.tsexplicitly enforces:Creating a
Userrecord without anemailimmediately fails Mongoose document validation (ValidationError: Path 'email' is required.), and throughout DevTrack, core controllers and auth middleware depend onuser.email.Current PR Behavior: The sync service cleanly rejects payloads without a valid email with a structured
AppError(400, 'Email address is required for user synchronization', 'EMAIL_REQUIRED')rather than crashing with unhandled runtime errors (TypeError: Cannot read properties of undefined).Question for Maintainers: Does DevTrack plan to support optional/email-less accounts in the future (which would require migrating the Mongoose schema and unique index on
email), or is the strict400 EMAIL_REQUIREDrejection the desired production contract?Verification & Test Results
New Regression Test Suite:
backend/src/__tests__/services/auth/ClerkUserSyncService.test.ts5.09s.400 EMAIL_REQUIRED).400 INVALID_EMAIL_FORMAT).E11000).clerkId.409 UNVERIFIED_EMAIL_CONFLICT).409 UNVERIFIED_EMAIL_CONFLICT).409 CLERK_IDENTITY_CONFLICT).UserProfileon subsequent sync.UserSettingson subsequent sync.UserProfilecreation.UserSettingscreation.Existing Test Suites & Build:
npm run build: Exit code 0 (tsc -p tsconfig.json && node fix-esm-imports.mjs).src/__tests__/middleware/: 9 passed, 0 failed.tests/integration-database.test.ts: 16 passed, 0 failed.src/__tests__/integration/: 8 passed, 0 failed.Baseline Disclosure:
src/__tests__/db/modelIndexes.test.tsreports a failure (missing: ['notification.model.ts']). Independent verification against a clean checkout of base commit5a57144confirmed this is an existing baseline failure in the repository, unrelated to this PR.Reviewer Checklist
status === 'verified').clerkIdcannot be overwritten.UserSettings,UserProfile) self-heal without duplicate-key errors.