Repository navigation
Conversation
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 37115256 | Triggered | Generic Password | 27e2c98 | backend/src/routes/auth.ts | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
PR Summary by QodoAdd Google authentication and persistent password changes
AI Description
Diagram
High-Level Assessment
Files changed (6)
|
Code Review by Qodo
1. Tokens for other apps grant access
|
| if (process.env.GOOGLE_CLIENT_ID && payload.aud !== process.env.GOOGLE_CLIENT_ID) { | ||
| res.status(401).json({ error: "Google token audience mismatch" }); | ||
| return; | ||
| } |
There was a problem hiding this comment.
1. Tokens for other apps grant access 🐞 Bug ⛨ Security
Audience validation runs only when GOOGLE_CLIENT_ID is configured, so a missing backend variable makes every Google OAuth client an accepted audience. The documented backend environment omits that variable, allowing a valid token obtained for another application to establish a session here.
Agent Prompt
## Issue description
The backend skips token audience validation when its Google client ID is missing, accepting tokens issued to unrelated applications.
## Issue Context
Google client configuration must be mandatory when Google authentication is enabled, and startup or authentication should fail closed if it is absent.
## Fix Focus Areas
- backend/src/routes/auth.ts[101-124]
- backend/.env.example[6-14]
- README.md[95-109]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| if (payload.email) { | ||
| targetEmail = payload.email.toLowerCase(); | ||
| if (payload.name) targetName = payload.name; | ||
| } |
There was a problem hiding this comment.
2. Reassigned emails inherit accounts 🐞 Bug ⛨ Security
The route associates a Google login with an existing local account solely through payload.email, despite parsing but never checking email_verified, hosted-domain authority, or Google's stable subject identifier. A Google account using a third-party email that is later reassigned can therefore enter the new owner's matching local account because Google does not remain authoritative for such addresses.
Agent Prompt
## Issue description
Google identities are linked to local accounts solely by mutable email, permitting an old holder of a reassigned third-party address to enter the new holder's account.
## Issue Context
Persist Google's stable `sub` identifier and provider metadata. Do not automatically merge an existing password account based only on a non-authoritative email; require authenticated account linking or another ownership challenge.
## Fix Focus Areas
- backend/src/routes/auth.ts[109-176]
- backend/src/db/schema/users.ts[5-16]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| const { credential, email: directEmail, name: directName } = req.body || {}; | ||
|
|
||
| let targetEmail = typeof directEmail === "string" ? directEmail.trim().toLowerCase() : ""; | ||
| let targetName = typeof directName === "string" ? directName.trim() : ""; |
There was a problem hiding this comment.
3. Anyone can sign in as another user 🐞 Bug ⛨ Security
/auth/google initializes targetEmail from the unauthenticated, caller-controlled email field and later signs an application token for the matching user without requiring a verified Google credential. Posting any existing account’s email, including an administrator’s, reaches lookup and token issuance, and the frontend deliberately sends this credential-free request whenever Google configuration or loading is unavailable.
Agent Prompt
## Issue description
Reject direct email/name authentication in the Google authentication endpoint and derive account identity exclusively from a successfully verified Google ID token. The endpoint currently accepts a caller-provided email without proof of identity, allowing authentication as any matching existing account.
## Issue Context
The normal email/password route verifies a bcrypt password before issuing a token, whereas the Google route can issue one based only on an email from the request body. The frontend fallback intentionally invokes this endpoint with only an email and name when Google configuration or loading is unavailable; production authentication must never derive identity from these direct fields.
## Fix Focus Areas
- backend/src/routes/auth.ts[95-176]
- frontend/src/components/google-auth-button.tsx[153-169]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| } else { | ||
| // In local/test mode if external Google call fails, fall back to decoding payload safely | ||
| const parts = credential.split("."); | ||
| if (parts.length === 3) { | ||
| const rawPayload = Buffer.from(parts[1], "base64").toString("utf-8"); | ||
| const parsed = JSON.parse(rawPayload); |
There was a problem hiding this comment.
4. Forged credentials can access accounts 🐞 Bug ⛨ Security
When Google's token endpoint returns a non-success response, /auth/google base64-decodes the submitted credential and trusts its email without validating the signature, issuer, expiry, audience, or verified-email status. An attacker can supply a fabricated three-part token containing a victim's email, which then reaches the normal account lookup and application-session signing flow.
Agent Prompt
## Issue description
Remove the behavior that decodes and trusts a credential after Google verification fails. Reject failed verification attempts, and require validation of the token's signature, expected audience, issuer, expiry, and verified-email status before using any identity claims.
## Issue Context
The fallback is not restricted to tests despite its comment. It converts an attacker-supplied token segment into `targetEmail`, which is then used to select an existing local user and issue an application session; every authentication attempt must fail closed when Google validation fails.
## Fix Focus Areas
- backend/src/routes/auth.ts[101-140]
- backend/src/routes/auth.ts[151-176]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| if (!user) { | ||
| // Generate a random secure hash for Google users who don't log in via traditional password | ||
| const randomPassword = `G-${Math.random().toString(36).slice(2)}-${Date.now()}`; | ||
| const passwordHash = await bcrypt.hash(randomPassword, 10); |
There was a problem hiding this comment.
5. Google users cannot change passwords 🐞 Bug ≡ Correctness
New Google accounts receive a generated random password that is never returned or otherwise made available to the account holder. The new change-password route requires that undisclosed current password, so these users cannot complete the Settings form to establish a password.
Agent Prompt
## Issue description
Provide a password-establishment flow for Google-created accounts that is authorized by an appropriate recent Google authentication, rather than requiring the generated password.
## Issue Context
The account creation path stores an unknowable random password, but the password update endpoint only permits changes after matching the current hash.
## Fix Focus Areas
- backend/src/routes/auth.ts[157-170]
- backend/src/routes/auth.ts[193-223]
- frontend/src/pages/settings.tsx[154-203]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| onClick={() => { | ||
| toast({ | ||
| title: "Google Account Connected", | ||
| description: `Primary email ${authUser?.email} is linked to Google sign-in.`, | ||
| }); | ||
| }} |
There was a problem hiding this comment.
6. Google connection status is fictitious 🐞 Bug ≡ Correctness
The Settings “Connect Google” handler only emits a success toast without invoking Google Identity Services, calling an account-linking endpoint, or persisting provider state, while connection status is inferred by checking whether the email contains google or ends in @gmail.com. Clicking the control therefore leaves the account unchanged but claims success, and ordinary Gmail addresses appear linked even though the backend only finds or creates users by email and stores no provider identity.
Agent Prompt
## Issue description
Replace the no-op success action and email-address heuristic with a verified Google account-linking flow and persisted provider-link state. The settings control must not report a successful connection unless authentication and account linking have completed and been stored.
## Issue Context
There is currently no backend linking operation: the existing Google route only finds or creates a user by email, and the user model exposes no persisted Google provider identity. Connection status must come from stored provider metadata rather than checking whether an email contains `google` or ends in `@gmail.com`. Until a secure linking flow exists, keep the control disabled and avoid success messaging.
## Fix Focus Areas
- frontend/src/pages/settings.tsx[934-961]
- backend/src/routes/auth.ts[95-191]
- backend/src/db/schema/users.ts[5-16]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| let [user] = await db | ||
| .select() | ||
| .from(usersTable) | ||
| .where(eq(usersTable.email, targetEmail)); |
There was a problem hiding this comment.
7. Concurrent first sign-ins can fail 🐞 Bug ☼ Reliability
/auth/google performs a separate lookup followed by an unconditional insert for a missing user, without atomic creation or duplicate-key recovery around the unique email column. Two concurrent first sign-ins for the same email can both observe no row, after which the losing insert raises an unhandled database error that reaches the generic application error handler.
Agent Prompt
## Issue description
Make Google user provisioning safe for concurrent first-time sign-ins. Use atomic account creation or recover from a duplicate-email insert by loading the canonical user before issuing the session.
## Issue Context
Email is a unique database key, but the route currently checks for a user and inserts one in separate operations without conflict handling. Two requests for the same new email can both observe no account and race to insert it, causing one request to reach the generic error handler with a database exception. Use an atomic upsert or `ON CONFLICT` strategy and then retrieve the canonical user; do not overwrite an existing account’s identity data during conflict recovery.
## Fix Focus Areas
- backend/src/routes/auth.ts[151-174]
- backend/src/db/schema/users.ts[5-16]
- backend/src/app.ts[47-64]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
No description provided.