{"id":"GHSA-92cr-jxw4-5wjg","revision":null,"records":[{"revision":"3da112f037304f7e9957521891b3a8c2","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-58269","aliases":[],"title":"Sync-in Server has a complete 2FA Bypass via `POST /api/auth/token`","description":"Sync-in Server is an open-source platform for file storage, sharing, collaboration, and syncing. Prior to version 2.4.0, `POST /api/auth/token` authenticates with username and password only, then calls `getTokens()`, which returns full access and refresh JWTs without checking whether the account has TOTP 2FA enabled. An attacker with stolen or phished credentials can bypass 2FA in a single request. The parallel login endpoint (`POST /api/auth/login`) correctly enforces 2FA by calling `setCookies(user, res, true)`, which gates on `user.twoFaEnabled`. Version 2.4.0 patches the issue.","state":0,"publishedAt":"2026-09-21T20:01:56.322+00:00","modifiedAt":"2026-09-24T22:38:27.013+00:00","affected":[{"ecosystem":"Vendor product","name":"server","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"Sync-in\",\n                    \"product\": \"server\",\n                    \"versions\": [\n                        {\n                            \"version\": \"< 2.4.0\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N","score":8.1,"severity":"HIGH"}],"references":["https://github.com/Sync-in/server/security/advisories/GHSA-92cr-jxw4-5wjg"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-58269","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-58269","identifiers":["CVE-2026-58269"]},"retained":false,"historicalAffected":[]},{"revision":"9e4b5facef504c8ea09166252ac6bdd7","observedAt":"2026-11-11T14:59:44.473+00:00","statement":{"source":"euvd","id":"EUVD-2026-84115","aliases":["CVE-2026-58269","GHSA-92cr-jxw4-5wjg"],"title":"Sync-in Server is an open-source platform for file storage, sharing, collaboration, and syncing. Prior to version 2.4.0, `POST /api/auth/token` authenticates with username and password only, then calls `getTokens()`, which returns full acce…","description":"Sync-in Server is an open-source platform for file storage, sharing, collaboration, and syncing. Prior to version 2.4.0, `POST /api/auth/token` authenticates with username and password only, then calls `getTokens()`, which returns full access and refresh JWTs without checking whether the account has TOTP 2FA enabled. An attacker with stolen or phished credentials can bypass 2FA in a single request. The parallel login endpoint (`POST /api/auth/login`) correctly enforces 2FA by calling `setCookies(user, res, true)`, which gates on `user.twoFaEnabled`. Version 2.4.0 patches the issue.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N","score":8.1,"severity":null}],"references":["https://github.com/Sync-in/server/security/advisories/GHSA-92cr-jxw4-5wjg"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-84115","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Sep 21, 2026, 8:01:56 PM","dateUpdated":"Sep 24, 2026, 10:38:27 PM"},"relatedAdvisories":[],"note":"EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON."},"key":"euvd:EUVD-2026-84115","identifiers":["EUVD-2026-84115","CVE-2026-58269","GHSA-92cr-jxw4-5wjg"]},"retained":false,"historicalAffected":[]},{"revision":"2a73a91e815f429d9461838dca671439","observedAt":"2026-10-25T14:19:16.843+00:00","statement":{"source":"nvd","id":"CVE-2026-58269","aliases":[],"title":"Sync-in Server is an open-source platform for file storage, sharing, collaboration, and syncing. Prior to version 2.4.0, `POST /api/auth/token` authenticates with username and password only, then calls `getTokens()`, which returns full acce…","description":"Sync-in Server is an open-source platform for file storage, sharing, collaboration, and syncing. Prior to version 2.4.0, `POST /api/auth/token` authenticates with username and password only, then calls `getTokens()`, which returns full access and refresh JWTs without checking whether the account has TOTP 2FA enabled. An attacker with stolen or phished credentials can bypass 2FA in a single request. The parallel login endpoint (`POST /api/auth/login`) correctly enforces 2FA by calling `setCookies(user, res, true)`, which gates on `user.twoFaEnabled`. Version 2.4.0 patches the issue.","state":0,"publishedAt":"2026-09-21T20:17:26.837+00:00","modifiedAt":"2026-09-24T23:17:12.46+00:00","affected":[],"metrics":[{"system":"CVSS 3.1 · security-advisories@github.com · Secondary","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N","score":8.1,"severity":"HIGH"}],"references":["https://github.com/Sync-in/server/security/advisories/GHSA-92cr-jxw4-5wjg"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-58269","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Deferred","weaknesses":["CWE-288"],"productCriteria":[],"sourceDates":{"published":"2026-09-21T20:17:26.837","lastModified":"2026-09-24T23:17:12.460"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-58269","identifiers":["CVE-2026-58269"]},"retained":false,"historicalAffected":[]},{"revision":"2acedf292822413ba0fadf4a02e5602d","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-92cr-jxw4-5wjg","aliases":["CVE-2026-58269"],"title":"Sync-in Server has a complete 2FA Bypass via `POST /api/auth/token`","description":"**Affected component:** Sync-in Server v2.3.0, `POST /api/auth/token` (`auth.controller.ts:50-55`).\n\n**Required attacker capability:** Valid username and password for a 2FA-enabled account.\n\n## Summary\n\n`POST /api/auth/token` authenticates with username and password only, then calls `getTokens()`, which returns unrestricted Bearer access and refresh JWTs without checking whether the account has TOTP 2FA enabled. An attacker who already knows valid credentials for a 2FA-enabled account can bypass 2FA in a single request.\n\nThe parallel login endpoint (`POST /api/auth/login`) correctly enforces 2FA by calling `setCookies(user, res, true)`, which gates on `user.twoFaEnabled` when server-side TOTP is enabled.\n\n## Details\n\nThe token endpoint at `auth.controller.ts:50-55` uses `AuthLocalGuard` (password-only) and calls `getTokens()` directly:\n```typescript\n// auth.controller.ts:50-55\n@Post(AUTH_ROUTE.TOKEN)\n@AuthTokenSkip()\n@UseGuards(AuthLocalGuard)\ntoken(@GetUser() user: UserModel): Promise<TokenResponseDto> {\n  return this.authManager.getTokens(user)\n}\n```\n`getTokens()` at `auth.service.ts:25-39` signs and returns access and refresh JWTs. It never reads `user.twoFaEnabled`:\n```typescript\n// auth.service.ts:25-39\nasync getTokens(user: UserModel, refresh = false): Promise<TokenResponseDto> {\n  const currentTime = currentTimeStamp()\n  // ...expiration logic...\n  return {\n    [TOKEN_TYPE.ACCESS]: await this.jwtSign(user, TOKEN_TYPE.ACCESS, accessExpiration),\n    [TOKEN_TYPE.REFRESH]: await this.jwtSign(user, TOKEN_TYPE.REFRESH, refreshExpiration),\n    // ...\n  }\n}\n```\nCompare with the login endpoint at `auth.controller.ts:30-35`, which calls `setCookies(user, res, true)`. Inside `setCookies()` at `auth.service.ts:45`, the 2FA gate fires:\n```typescript\n// auth.service.ts:45\nconst verify2Fa = init2FaVerify && configuration.auth.mfa.totp.enabled && user.twoFaEnabled\n```\nWhen `verify2Fa` is true, `setCookies()` issues only a restricted `ACCESS_2FA` token and requires the user to complete `POST /api/auth/2fa/login/verify` before receiving full session cookies. The token endpoint has no equivalent gate.\n\n## PoC\n\n### Prerequisites\n\n- A Sync-in instance with TOTP 2FA enabled server-wide.\n- A user account with 2FA enrolled (the target).\n- The target's valid login and password, but not the TOTP secret or current TOTP code.\n\n### Steps\n\n1. **Enable 2FA on the target account.** Log in as the target user, navigate to Settings, and enable TOTP two-factor authentication.\n\n2. **Confirm normal login requires 2FA.** Log out. Log back in with the target's credentials. The UI presents a TOTP code prompt before granting access, and the API response contains only `token.access_2fa_expiration` (a restricted partial token):\n```\nPOST /api/auth/login\n{\"login\":\"test\",\"password\":\"...\"}\n\nResponse: {\"user\":{\"twoFaEnabled\":true},\"server\":{\"twoFaEnabled\":true},\"token\":{\"access_2fa_expiration\":1781234379}}\n```\n3. **Bypass 2FA via the token endpoint.** Send the same credentials to `/api/auth/token`:\n```\nPOST /api/auth/token\n{\"login\":\"test\",\"password\":\"...\"}\n\nResponse:\n{\n  \"access\": \"eyJhbGciOiJIUzI1NiIs...\",\n  \"refresh\": \"eyJhbGciOiJIUzI1NiIs...\",\n  \"access_expiration\": 1781235890,\n  \"refresh_expiration\": 1781248490\n}\n```\nUnrestricted Bearer access and refresh JWTs are returned. No TOTP code was required.\n\n4. **Confirm API access.** Use the token on a protected endpoint:\n```\nGET /api/users/me\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIs...\n\nResponse: {\"user\":{\"id\":16,\"login\":\"test\",\"email\":\"test@lab.local\",\"twoFaEnabled\":true,...}}\n```\nThe server returns the user profile. Protected API endpoints that accept Bearer authentication are accessible as the target user. No TOTP code was required at any step.\n\n### Measured observations\n\n- The login endpoint (`/api/auth/login`) correctly returns a restricted 2FA-pending response.\n- The token endpoint (`/api/auth/token`) returns unrestricted Bearer JWTs with the same credentials and no TOTP.\n- The returned Bearer token grants access to protected API endpoints as a fully authenticated user, though cookie-specific flows may differ.\n\n## Impact\n\nAn attacker who already knows valid credentials for a 2FA-enabled account can obtain unrestricted Bearer access and refresh JWTs in a single HTTP request, without knowing the TOTP secret or possessing the authenticator device. 2FA security is bypassed for Bearer-token API authentication.\n\n## Remediation\n\nGate the token endpoint behind the same 2FA policy used by the login route. After `AuthLocalGuard` validates the username and password, require a valid TOTP code when server-side TOTP is enabled and `user.twoFaEnabled` is true, before calling `getTokens()`.","state":0,"publishedAt":"2026-09-22T14:46:30+00:00","modifiedAt":"2026-09-22T15:00:48.8995643+00:00","affected":[{"ecosystem":"npm","name":"@sync-in/server","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"2.4.0"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/Sync-in/server/security/advisories/GHSA-92cr-jxw4-5wjg","https://nvd.nist.gov/vuln/detail/CVE-2026-58269","https://github.com/Sync-in/server/pull/228","https://github.com/Sync-in/server/commit/3ec74e2ea1f538fe1a3ac9487bdf24a19e548361","https://github.com/Sync-in/server","https://github.com/Sync-in/server/releases/tag/v2.4.0"],"sourceUrl":"https://github.com/advisories/GHSA-92cr-jxw4-5wjg","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-92cr-jxw4-5wjg","identifiers":["GHSA-92cr-jxw4-5wjg","CVE-2026-58269"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-11-12T11:55:28.1860721+00:00","complete":true,"records":1779,"lastAttemptAt":"2026-11-12T11:55:28.1860721+00:00","lastSuccessAt":"2026-11-12T11:55:28.4130785+00:00","error":null,"lastVerifiedAt":"2026-11-12T11:55:28.4130791+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-64752486c567b55b31fb0d7225f5222bcd0019564ac0ac5f0649e242c7b19299-4a4604796d7c0adea2c1c677026f25a1e039e4a95710b02ad846575329daaa79","complete":true,"records":424651,"lastAttemptAt":"2026-11-12T11:53:33.8199862+00:00","lastSuccessAt":"2026-11-12T11:53:33.7811873+00:00","error":null,"lastVerifiedAt":"2026-11-12T11:53:33.8199862+00:00","snapshotPublishedAt":"2026-11-12T11:27:22+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-0580dcc98aaa46a8935f8ff576f25037","complete":true,"records":13764,"lastAttemptAt":"2026-11-12T11:56:20.2141865+00:00","lastSuccessAt":"2026-11-12T11:56:20.209+00:00","error":null,"lastVerifiedAt":"2026-11-12T11:56:20.209+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13817,"expectedIdentifiers":13817,"failedIdentifiers":0},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-12T11:55:28.1860721+00:00","complete":true,"records":1097,"lastAttemptAt":"2026-11-12T11:55:28.1860721+00:00","lastSuccessAt":"2026-11-12T11:55:28.4142299+00:00","error":null,"lastVerifiedAt":"2026-11-12T11:55:28.4142304+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-ea8d0b9744d8407d9df5932458afeb6a","complete":false,"records":13764,"lastAttemptAt":"2026-11-12T11:55:53.6222651+00:00","lastSuccessAt":"2026-11-12T11:55:53.618+00:00","error":null,"lastVerifiedAt":"2026-11-12T11:55:53.618+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13313,"expectedIdentifiers":13817,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-3562b6c78fd1bd0f0b55daf66a0926ae24f65e462df7f6d928caad458fc696bf","complete":true,"records":9947,"lastAttemptAt":"2026-11-12T11:55:28.0344457+00:00","lastSuccessAt":"2026-11-11T04:27:43.6877707+00:00","error":null,"lastVerifiedAt":"2026-11-12T11:55:28.0344457+00:00","snapshotPublishedAt":"2026-11-11T03:32:46+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-456002455e0ab94bb92c95476d4e6d175c104cd594749982afd96c893728ecbc","complete":true,"records":2010,"lastAttemptAt":"2026-11-12T11:53:33.8856695+00:00","lastSuccessAt":"2026-11-11T02:36:58.1276999+00:00","error":null,"lastVerifiedAt":"2026-11-12T11:53:33.8856695+00:00","snapshotPublishedAt":"2026-11-11T01:17:51+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-f46f74c6a30a9b6e4cfb481719c6d35521ebec2d53ebf163223d093ae587eb9d","complete":true,"records":3106,"lastAttemptAt":"2026-11-12T11:55:28.1484531+00:00","lastSuccessAt":"2026-11-12T09:55:31.1176285+00:00","error":null,"lastVerifiedAt":"2026-11-12T11:55:28.1484531+00:00","snapshotPublishedAt":"2026-11-12T09:48:13+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-e59fd13399d7070c31f5f25102a6bcd537ccba91d773c8427fcf0d07ea0fe2d5","complete":true,"records":231700,"lastAttemptAt":"2026-11-12T11:55:27.8998515+00:00","lastSuccessAt":"2026-11-12T11:55:26.4268762+00:00","error":null,"lastVerifiedAt":"2026-11-12T11:55:27.8998515+00:00","snapshotPublishedAt":"2026-11-12T11:33:13+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}