{"id":"CVE-2026-58271","aliases":["EUVD-2026-84112","GHSA-274f-6w77-8qm9"],"status":"published","title":"@sync-in/server vulnerable to TOTP Brute-Force via `POST /api/app/sync/register`","description":"Sync-in Server is an open-source platform for file storage, sharing, collaboration, and syncing. Prior to version 2.4.0, `POST /api/app/sync/register` accepts credentials and a TOTP code to register a desktop sync client. On a failed TOTP, `SyncClientsManager.register()` calls `updateAccesses(user, ip, false)`, which hits a freeze branch that writes `passwordAttempts` back unchanged. The counter never reaches `USER_MAX_PASSWORD_ATTEMPTS` (10) and the lockout gate never fires. A successful guess returns a `{clientId, clientToken}` pair. The token can be exchanged via `POST /api/app/sync/auth/cookie` for a full JWT. While the code is valid, the attacker can also call `POST /api/auth/2fa/disable` to permanently remove MFA. Version 2.4.0 patches the issue.","severity":{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.00219,"percentile":0.12476,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-307"],"published":"2026-09-21T19:50:14Z","modified":"2026-10-28T02:30:42Z","fixes":[{"ecosystem":"npm","package":"@sync-in/server","fixed_in":["2.4.0"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"@sync-in/server","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"2.3.0"},{"fixed":"2.4.0"}]}]},{"source":"osv","ecosystem":"npm","package":"@sync-in/server","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"2.4.0"}]}]}],"products":[{"vendor":"devolutions","product":"server"},{"vendor":"sync-in","product":"server"}],"references":[{"url":"https://github.com/Sync-in/server/security/advisories/GHSA-274f-6w77-8qm9","tags":["x_refsource_CONFIRM","exploit","advisory","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-58271","tags":["advisory"]},{"url":"https://github.com/Sync-in/server/pull/228","tags":["web"]},{"url":"https://github.com/Sync-in/server/commit/b13a4aad5c2b38fe8231a0d007cd08a086ec5bdb","tags":["web"]},{"url":"https://github.com/Sync-in/server/releases/tag/v2.4.0","tags":["web"]},{"url":"https://github.com/advisories/GHSA-274f-6w77-8qm9"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/58xxx/CVE-2026-58271.json","tags":["advisory"]},{"url":"https://github.com/Sync-in/server","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-58271","title":"@sync-in/server vulnerable to TOTP Brute-Force via `POST /api/app/sync/register`","description":"Sync-in Server is an open-source platform for file storage, sharing, collaboration, and syncing. Prior to version 2.4.0, `POST /api/app/sync/register` accepts credentials and a TOTP code to register a desktop sync client. On a failed TOTP, `SyncClientsManager.register()` calls `updateAccesses(user, ip, false)`, which hits a freeze branch that writes `passwordAttempts` back unchanged. The counter never reaches `USER_MAX_PASSWORD_ATTEMPTS` (10) and the lockout gate never fires. A successful guess returns a `{clientId, clientToken}` pair. The token can be exchanged via `POST /api/app/sync/auth/cookie` for a full JWT. While the code is valid, the attacker can also call `POST /api/auth/2fa/disable` to permanently remove MFA. Version 2.4.0 patches the issue.","status":"published","published":"2026-09-21T19:50:14.539Z","modified":"2026-09-24T22:36:41.527Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N","level":"medium","assessor":"cna"}],"cwes":["CWE-307"],"updated_at":"2026-11-02T13:47:39.876248Z"}],"euvd":[{"id":"EUVD-2026-84112","description":"Sync-in Server is an open-source platform for file storage, sharing, collaboration, and syncing. Prior to version 2.4.0, `POST /api/app/sync/register` accepts credentials and a TOTP code to register a desktop sync client. On a failed TOTP, `SyncClientsManager.register()` calls `updateAccesses(user, ip, false)`, which hits a freeze branch that writes `passwordAttempts` back unchanged. The counter never reaches `USER_MAX_PASSWORD_ATTEMPTS` (10) and the lockout gate never fires. A successful guess returns a `{clientId, clientToken}` pair. The token can be exchanged via `POST /api/app/sync/auth/cookie` for a full JWT. While the code is valid, the attacker can also call `POST /api/auth/2fa/disable` to permanently remove MFA. Version 2.4.0 patches the issue.","status":"published","published":"2026-09-21T19:50:14Z","modified":"2026-09-24T22:36:41Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N","level":"medium"}],"updated_at":"2026-11-02T17:27:55.846756Z"}],"ghsa":[{"id":"GHSA-274f-6w77-8qm9","title":"@sync-in/server vulnerable to TOTP Brute-Force via `POST /api/app/sync/register`","description":"**Affected component:** Sync-in Server v2.3.0, `POST /api/app/sync/register`.\n\n**Required attacker capability:** Valid login and password for a TOTP-enabled account with desktop sync permission.\n\n## Summary\n\n`POST /api/app/sync/register` accepts credentials and a TOTP code to register a desktop sync client. In the vulnerable version, on a failed TOTP attempt, `SyncClientsManager.register()` called `updateAccesses(user, ip, false)`, which hit a freeze branch that wrote `passwordAttempts` back unchanged. The counter never reached `USER_MAX_PASSWORD_ATTEMPTS` (10), so the account lockout gate never fired for repeated TOTP failures through this endpoint.\n\nA successful TOTP guess registers a sync client and returns a `{clientId, clientToken}` pair, provided the account has the required desktop app permission and the registration payload is valid. The token can then be exchanged via `POST /api/app/sync/auth/cookie` for an authenticated session. While the guessed TOTP code is still valid, and because the attacker already knows the password, the attacker can also call `POST /api/auth/2fa/disable` to remove MFA.\n\n## Details\n\nThe endpoint is declared at `sync.controller.ts` line 71. `@AuthTokenSkip()` bypasses the bearer-token guard, so the route is reachable without any prior session:\n```typescript\n@Post(SYNC_ROUTE.REGISTER)\n@AuthTokenSkip()\nregister(@Body() syncClientRegistrationDto: SyncClientRegistrationDto, @Req() req: FastifyRequest): Promise\u003cSyncClientAuthRegistration\u003e {\n  return this.syncClientsManager.register(syncClientRegistrationDto, req.ip)\n}\n```\nInside `SyncClientsManager.register()`, after both the TOTP code and the recovery code are rejected, the handler fires a fire-and-forget access update and throws (`sync-clients-manager.service.ts` line 73):\n```typescript\nthis.usersManager.updateAccesses(user, ip, false).catch((e: Error) =\u003e this.logger.error({ tag: this.register.name, msg: `${e}` }))\nthrow new HttpException(authCode.message, HttpStatus.UNAUTHORIZED)\n```\n\nIn the vulnerable version, `updateAccesses()` at `users-manager.service.ts` line 182 defaulted `isAuthTwoFa` to `false`:\n\n```typescript\nasync updateAccesses(user: UserModel, ip: string, success: boolean, isAuthTwoFa = false) {\n  let passwordAttempts: number\n  if (!isAuthTwoFa \u0026\u0026 configuration.auth.mfa.totp.enabled \u0026\u0026 user.twoFaEnabled) {\n    passwordAttempts = user.passwordAttempts\n  } else {\n    passwordAttempts = success ? 0 : Math.min(user.passwordAttempts + 1, USER_MAX_PASSWORD_ATTEMPTS)\n  }\n  await this.usersQueries.updateUserOrGuest(user.id, {\n    ...\n    passwordAttempts: passwordAttempts,\n    isActive: user.isActive \u0026\u0026 passwordAttempts \u003c USER_MAX_PASSWORD_ATTEMPTS\n  })\n}\n```\n\nWhen `register()` called `updateAccesses(user, ip, false)`, `isAuthTwoFa` defaulted to `false`. The condition on line 184 evaluated to `true` when TOTP was enabled site-wide and the account had it active. The `else` branch with `Math.min(user.passwordAttempts + 1, ...)` was never reached. `passwordAttempts` was written back unchanged, and the lockout gate in `validateUserAccess()` at line 89 never fired for repeated TOTP failures through this endpoint.\n\nThe freeze was designed for the web login flow, where a correct password at `POST /api/auth/login` produces a partial session and the counter should be preserved until `POST /api/auth/2fa/login/verify` completes. That route calls `authProvider2FA.verify(body, req, true)`, which passes `isAuthTwoFa=true` into `updateAccesses()` and correctly increments on 2FA failure. The `register()` endpoint reused `updateAccesses()` for an outright TOTP rejection while passing the default `isAuthTwoFa=false`, triggering the freeze incorrectly.\n\nThe same freeze also applied to `logUser()` (`users-manager.service.ts` line 69), called by both `POST /api/auth/login` and `POST /api/auth/token`. On a wrong password for a 2FA-enabled account, `updateAccesses(user, ip, false)` was called without an `isAuthTwoFa` argument, so the freeze fired and `passwordAttempts` was preserved rather than incremented.\n\n## PoC\n\nFirst, create a test account with TOTP MFA enabled and desktop sync permission. Then run the following:\n\n[poc_totp_bruteforce.py](https://github.com/user-attachments/files/28857878/poc_totp_bruteforce.py)\n\n```bash\n$ python3 poc_totp_bruteforce.py --url http://192.168.16.132:8080 --user mfatest --password 'Str0ngP@ss99!' --concurrency 4 --batch 100\n```\n\nExample output:\n\n```text\n[*] Target      : http://192.168.16.132:8080\n[*] Account     : mfatest\n[*] Concurrency : 4\n\n[*] Step 1: Confirming credentials and 2FA status...\n[+] Credentials valid, 2FA active.\n\n[*] Step 2: Brute-forcing TOTP codes (4 workers)...\n  Ranges: W0=000000-250000, W1=250000-500000, W2=500000-750000, W3=750000-1000000\n  [W2]   1,100 total | 11.3 req/s | retries: 0\n      \u003csnip\u003e\n  [W1] 195,400 total | 11.0 req/s | retries: 0\n\n[*] Step 3: Results\n  Total attempts : 195,907\n  Time elapsed   : 17769.5s (296.2min)\n  Average RPS    : 11.0\n\n[+] VALID TOTP CODE FOUND : 026961\n[+] clientId              : 13951b88-03d4-4854-8a29-cd8921d73d82\n[+] clientToken           : c92ef5ca-7432-44d0-8a94-56398bfe4117\n\n[*] Step 4: Confirming access and attempting to disable 2FA...\n  [+] Authenticated as : mfatest (id=3, role=1)\n      passwordAttempts : 0\n  [+] 2FA DISABLED. Account 'mfatest' now accessible with password alone.\n```\n\n**Measured observations:**\n\n- No account lockout was observed across 195,907 failed TOTP attempts in this test against the vulnerable version.\n- The `clientToken` was exchanged for an authenticated session.\n- MFA was disabled via `POST /api/auth/2fa/disable` while the guessed TOTP code was still valid and because the attacker already knew the account password.\n\n## Impact\n\nAn attacker who already knows valid credentials for a TOTP-enabled account with desktop sync permission can brute-force the second factor through `POST /api/app/sync/register` without triggering account lockout.\n\nWith `drift: 1`, 3 of 1,000,000 six-digit codes are valid per 30-second window (`p = 3/1,000,000`), giving an expected 333,333 attempts to find a valid code.\n\nAt 3 r/s, measured against a default single-worker deployment:\n\n| Success probability | Attempts | Time at 3 r/s |\n|---|---:|---:|\n| 50% | 231,049 | 21.4 h |\n| 90% | 767,528 | 71.1 h |\n| 95% | 998,577 | 92.5 h |\n| 99% | 1,535,056 | 142.1 h |\n| Expected (mean) | 333,333 | 30.9 h |\n\nDeployments with `server.workers \u003e 1` may allow higher throughput, depending on CPU capacity and other bottlenecks. Throughput is heavily influenced by server-side password verification cost, worker count, database latency, and deployment limits, not only by the attacker's network speed.\n\n## Remediation\n\nAdd `\u0026\u0026 success` to the freeze condition at `users-manager.service.ts` line 184:\n\n```typescript\n// Before\nif (!isAuthTwoFa \u0026\u0026 configuration.auth.mfa.totp.enabled \u0026\u0026 user.twoFaEnabled) {\n\n// After\nif (!isAuthTwoFa \u0026\u0026 configuration.auth.mfa.totp.enabled \u0026\u0026 user.twoFaEnabled \u0026\u0026 success) {\n```\n\nThe freeze still applies when a password succeeds but 2FA is pending, which was its intended purpose. A failed TOTP at `register()` and a failed password at `login`/`token` both fall through to the increment path, restoring lockout after 10 failures.\n\nFor defense-in-depth, apply an IP and/or account-based rate limiter to `POST /api/app/sync/register` and other pre-auth credential endpoints.","status":"published","published":"2026-09-22T14:44:43Z","modified":"2026-09-22T14:44:46Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N","level":"medium"}],"cwes":["CWE-307"],"updated_at":"2026-11-02T14:41:19.455935Z"}],"nvd":[{"id":"CVE-2026-58271","description":"Sync-in Server is an open-source platform for file storage, sharing, collaboration, and syncing. Prior to version 2.4.0, `POST /api/app/sync/register` accepts credentials and a TOTP code to register a desktop sync client. On a failed TOTP, `SyncClientsManager.register()` calls `updateAccesses(user, ip, false)`, which hits a freeze branch that writes `passwordAttempts` back unchanged. The counter never reaches `USER_MAX_PASSWORD_ATTEMPTS` (10) and the lockout gate never fires. A successful guess returns a `{clientId, clientToken}` pair. The token can be exchanged via `POST /api/app/sync/auth/cookie` for a full JWT. While the code is valid, the attacker can also call `POST /api/auth/2fa/disable` to permanently remove MFA. Version 2.4.0 patches the issue.","status":"published","published":"2026-09-21T20:17:26.993Z","modified":"2026-09-24T23:17:12.723Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N","level":"medium","assessor":"secondary"}],"cwes":["CWE-307"],"updated_at":"2026-11-02T14:12:50.368368Z"}],"osv":[{"id":"CVE-2026-58271","title":"@sync-in/server vulnerable to TOTP Brute-Force via `POST /api/app/sync/register`","description":"Sync-in Server is an open-source platform for file storage, sharing, collaboration, and syncing. Prior to version 2.4.0, `POST /api/app/sync/register` accepts credentials and a TOTP code to register a desktop sync client. On a failed TOTP, `SyncClientsManager.register()` calls `updateAccesses(user, ip, false)`, which hits a freeze branch that writes `passwordAttempts` back unchanged. The counter never reaches `USER_MAX_PASSWORD_ATTEMPTS` (10) and the lockout gate never fires. A successful guess returns a `{clientId, clientToken}` pair. The token can be exchanged via `POST /api/app/sync/auth/cookie` for a full JWT. While the code is valid, the attacker can also call `POST /api/auth/2fa/disable` to permanently remove MFA. Version 2.4.0 patches the issue.","status":"published","published":"2026-09-21T19:50:14.539Z","modified":"2026-10-28T02:30:42.052258736Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N","level":"medium"}],"cwes":["CWE-307"],"updated_at":"2026-11-02T15:45:12.016252Z"},{"id":"GHSA-274f-6w77-8qm9","title":"@sync-in/server vulnerable to TOTP Brute-Force via `POST /api/app/sync/register`","description":"**Affected component:** Sync-in Server v2.3.0, `POST /api/app/sync/register`.\n\n**Required attacker capability:** Valid login and password for a TOTP-enabled account with desktop sync permission.\n\n## Summary\n\n`POST /api/app/sync/register` accepts credentials and a TOTP code to register a desktop sync client. In the vulnerable version, on a failed TOTP attempt, `SyncClientsManager.register()` called `updateAccesses(user, ip, false)`, which hit a freeze branch that wrote `passwordAttempts` back unchanged. The counter never reached `USER_MAX_PASSWORD_ATTEMPTS` (10), so the account lockout gate never fired for repeated TOTP failures through this endpoint.\n\nA successful TOTP guess registers a sync client and returns a `{clientId, clientToken}` pair, provided the account has the required desktop app permission and the registration payload is valid. The token can then be exchanged via `POST /api/app/sync/auth/cookie` for an authenticated session. While the guessed TOTP code is still valid, and because the attacker already knows the password, the attacker can also call `POST /api/auth/2fa/disable` to remove MFA.\n\n## Details\n\nThe endpoint is declared at `sync.controller.ts` line 71. `@AuthTokenSkip()` bypasses the bearer-token guard, so the route is reachable without any prior session:\n```typescript\n@Post(SYNC_ROUTE.REGISTER)\n@AuthTokenSkip()\nregister(@Body() syncClientRegistrationDto: SyncClientRegistrationDto, @Req() req: FastifyRequest): Promise\u003cSyncClientAuthRegistration\u003e {\n  return this.syncClientsManager.register(syncClientRegistrationDto, req.ip)\n}\n```\nInside `SyncClientsManager.register()`, after both the TOTP code and the recovery code are rejected, the handler fires a fire-and-forget access update and throws (`sync-clients-manager.service.ts` line 73):\n```typescript\nthis.usersManager.updateAccesses(user, ip, false).catch((e: Error) =\u003e this.logger.error({ tag: this.register.name, msg: `${e}` }))\nthrow new HttpException(authCode.message, HttpStatus.UNAUTHORIZED)\n```\n\nIn the vulnerable version, `updateAccesses()` at `users-manager.service.ts` line 182 defaulted `isAuthTwoFa` to `false`:\n\n```typescript\nasync updateAccesses(user: UserModel, ip: string, success: boolean, isAuthTwoFa = false) {\n  let passwordAttempts: number\n  if (!isAuthTwoFa \u0026\u0026 configuration.auth.mfa.totp.enabled \u0026\u0026 user.twoFaEnabled) {\n    passwordAttempts = user.passwordAttempts\n  } else {\n    passwordAttempts = success ? 0 : Math.min(user.passwordAttempts + 1, USER_MAX_PASSWORD_ATTEMPTS)\n  }\n  await this.usersQueries.updateUserOrGuest(user.id, {\n    ...\n    passwordAttempts: passwordAttempts,\n    isActive: user.isActive \u0026\u0026 passwordAttempts \u003c USER_MAX_PASSWORD_ATTEMPTS\n  })\n}\n```\n\nWhen `register()` called `updateAccesses(user, ip, false)`, `isAuthTwoFa` defaulted to `false`. The condition on line 184 evaluated to `true` when TOTP was enabled site-wide and the account had it active. The `else` branch with `Math.min(user.passwordAttempts + 1, ...)` was never reached. `passwordAttempts` was written back unchanged, and the lockout gate in `validateUserAccess()` at line 89 never fired for repeated TOTP failures through this endpoint.\n\nThe freeze was designed for the web login flow, where a correct password at `POST /api/auth/login` produces a partial session and the counter should be preserved until `POST /api/auth/2fa/login/verify` completes. That route calls `authProvider2FA.verify(body, req, true)`, which passes `isAuthTwoFa=true` into `updateAccesses()` and correctly increments on 2FA failure. The `register()` endpoint reused `updateAccesses()` for an outright TOTP rejection while passing the default `isAuthTwoFa=false`, triggering the freeze incorrectly.\n\nThe same freeze also applied to `logUser()` (`users-manager.service.ts` line 69), called by both `POST /api/auth/login` and `POST /api/auth/token`. On a wrong password for a 2FA-enabled account, `updateAccesses(user, ip, false)` was called without an `isAuthTwoFa` argument, so the freeze fired and `passwordAttempts` was preserved rather than incremented.\n\n## PoC\n\nFirst, create a test account with TOTP MFA enabled and desktop sync permission. Then run the following:\n\n[poc_totp_bruteforce.py](https://github.com/user-attachments/files/28857878/poc_totp_bruteforce.py)\n\n```bash\n$ python3 poc_totp_bruteforce.py --url http://192.168.16.132:8080 --user mfatest --password 'Str0ngP@ss99!' --concurrency 4 --batch 100\n```\n\nExample output:\n\n```text\n[*] Target      : http://192.168.16.132:8080\n[*] Account     : mfatest\n[*] Concurrency : 4\n\n[*] Step 1: Confirming credentials and 2FA status...\n[+] Credentials valid, 2FA active.\n\n[*] Step 2: Brute-forcing TOTP codes (4 workers)...\n  Ranges: W0=000000-250000, W1=250000-500000, W2=500000-750000, W3=750000-1000000\n  [W2]   1,100 total | 11.3 req/s | retries: 0\n      \u003csnip\u003e\n  [W1] 195,400 total | 11.0 req/s | retries: 0\n\n[*] Step 3: Results\n  Total attempts : 195,907\n  Time elapsed   : 17769.5s (296.2min)\n  Average RPS    : 11.0\n\n[+] VALID TOTP CODE FOUND : 026961\n[+] clientId              : 13951b88-03d4-4854-8a29-cd8921d73d82\n[+] clientToken           : c92ef5ca-7432-44d0-8a94-56398bfe4117\n\n[*] Step 4: Confirming access and attempting to disable 2FA...\n  [+] Authenticated as : mfatest (id=3, role=1)\n      passwordAttempts : 0\n  [+] 2FA DISABLED. Account 'mfatest' now accessible with password alone.\n```\n\n**Measured observations:**\n\n- No account lockout was observed across 195,907 failed TOTP attempts in this test against the vulnerable version.\n- The `clientToken` was exchanged for an authenticated session.\n- MFA was disabled via `POST /api/auth/2fa/disable` while the guessed TOTP code was still valid and because the attacker already knew the account password.\n\n## Impact\n\nAn attacker who already knows valid credentials for a TOTP-enabled account with desktop sync permission can brute-force the second factor through `POST /api/app/sync/register` without triggering account lockout.\n\nWith `drift: 1`, 3 of 1,000,000 six-digit codes are valid per 30-second window (`p = 3/1,000,000`), giving an expected 333,333 attempts to find a valid code.\n\nAt 3 r/s, measured against a default single-worker deployment:\n\n| Success probability | Attempts | Time at 3 r/s |\n|---|---:|---:|\n| 50% | 231,049 | 21.4 h |\n| 90% | 767,528 | 71.1 h |\n| 95% | 998,577 | 92.5 h |\n| 99% | 1,535,056 | 142.1 h |\n| Expected (mean) | 333,333 | 30.9 h |\n\nDeployments with `server.workers \u003e 1` may allow higher throughput, depending on CPU capacity and other bottlenecks. Throughput is heavily influenced by server-side password verification cost, worker count, database latency, and deployment limits, not only by the attacker's network speed.\n\n## Remediation\n\nAdd `\u0026\u0026 success` to the freeze condition at `users-manager.service.ts` line 184:\n\n```typescript\n// Before\nif (!isAuthTwoFa \u0026\u0026 configuration.auth.mfa.totp.enabled \u0026\u0026 user.twoFaEnabled) {\n\n// After\nif (!isAuthTwoFa \u0026\u0026 configuration.auth.mfa.totp.enabled \u0026\u0026 user.twoFaEnabled \u0026\u0026 success) {\n```\n\nThe freeze still applies when a password succeeds but 2FA is pending, which was its intended purpose. A failed TOTP at `register()` and a failed password at `login`/`token` both fall through to the increment path, restoring lockout after 10 failures.\n\nFor defense-in-depth, apply an IP and/or account-based rate limiter to `POST /api/app/sync/register` and other pre-auth credential endpoints.","status":"published","published":"2026-09-22T14:44:43Z","modified":"2026-09-22T15:00:47.447960175Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N","level":"medium"}],"cwes":["CWE-307"],"updated_at":"2026-11-02T15:46:33.956911Z"}]}}
