{"record":{"id":"944e98f94563b86c","repo":"can1357/oh-my-pi","slug":"security-scan-authentication-identity-mismatch","errorCode":null,"errorMessage":"Security scan authentication identity mismatch","messagePattern":"Security scan authentication identity mismatch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/security/auth.ts","lineNumber":29,"sourceCode":"\nexport function assertSecurityIdentityMatches(\n\taccount: SecurityAccountRef,\n\tresolution: {\n\t\tcredentialId?: number;\n\t\taccountId?: string;\n\t\temail?: string;\n\t\torgId?: string;\n\t\torgName?: string;\n\t},\n): void {\n\tif (\n\t\taccount.credentialId !== resolution.credentialId ||\n\t\t(account.accountId !== undefined && account.accountId !== resolution.accountId) ||\n\t\t(account.email !== undefined && account.email !== resolution.email) ||\n\t\t(account.organizationId !== undefined && account.organizationId !== resolution.orgId) ||\n\t\t(account.organizationName !== undefined && account.organizationName !== resolution.orgName)\n\t) {\n\t\tthrow new Error(\"Security scan authentication identity mismatch\");\n\t}\n}\n\nexport function selectSecurityAccount(\n\tauthStorage: AuthStorage,\n\tprovider: string,\n\trequestedCredentialId?: number,\n\tsessionId?: string,\n): SecurityAccountRef {\n\tconst accounts = authStorage.listOAuthAccounts(provider, sessionId);\n\tconst selected =\n\t\trequestedCredentialId !== undefined\n\t\t\t? accounts.find(account => account.credentialId === requestedCredentialId)\n\t\t\t: (accounts.find(account => account.active) ?? (accounts.length === 1 ? accounts[0] : undefined));\n\tif (!selected) {\n\t\tif (accounts.length === 0) throw new Error(`Security scans require a stored OAuth account for ${provider}`);\n\t\tif (requestedCredentialId !== undefined) {\n\t\t\tthrow new Error(`Security OAuth credential ${requestedCredentialId} is not available for ${provider}`);","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/security/auth.ts#L11-L47","documentation":"assertSecurityIdentityMatches verifies that a resolved OAuth credential's identity (credentialId, accountId, email, organizationId, organizationName) matches the account reference supplied for a security scan. Any field present on both sides that disagrees causes a throw, preventing scans from running under a different identity than requested.","triggerScenarios":"Calling the security-scan auth path with an account ref whose credentialId/accountId/email/org fields do not match what the auth storage resolution returns.","commonSituations":"Stale cached account metadata after re-authenticating with a different account; org name changed server-side; passing a credentialId belonging to another user/org.","solutions":["Re-select the account via selectSecurityAccount so the ref is derived from current auth-storage data","Re-authenticate with the OAuth provider to refresh account metadata","Update the caller to pass the correct credentialId/account identity"],"exampleFix":"// before\nassertSecurityIdentityMatches({ credentialId: \"old-cred\", email: \"a@x.com\" }, resolution);\n// after\nconst account = selectSecurityAccount(authStorage, provider, undefined, sessionId);\nassertSecurityIdentityMatches(account, resolution);","handlingStrategy":"validation","validationCode":"const accounts = authStorage.listOAuthAccounts(provider, sessionId);\nconst account = requestedCredentialId\n  ? accounts.find(a => a.credentialId === requestedCredentialId)\n  : accounts.find(a => a.active);\nif (!account) throw new Error(\"no matching stored OAuth account for security scan\");","typeGuard":"null","tryCatchPattern":"try {\n  assertSecurityIdentityMatches(account, resolution);\n} catch (err) {\n  if (err instanceof Error && err.message === \"Security scan authentication identity mismatch\") {\n    // refresh account ref from auth storage and re-authenticate\n    account = selectSecurityAccount(authStorage, provider, undefined, sessionId);\n  } else throw err;\n}","preventionTips":["Always derive account refs from selectSecurityAccount rather than caching them","Re-authenticate after account/org changes so stored metadata is current","Verify credentialId/accountId/email/org fields agree before invoking scan flows"],"tags":["auth","oauth","security"],"backgroundTag":"oauth-identity-mismatch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}