{"id":"CVE-2026-77937","kind":"vulnerability","aliases":["CVE-2026-77937"],"related":[],"title":"Letta: user_id header lets API callers impersonate other tenants","description":"Letta through 0.16.8 contains an authentication bypass vulnerability that allows API callers to impersonate other users by supplying a self-asserted user_id HTTP header. Attackers can set user_id to another tenant's ID, even with LETTA_SERVER_SECURE enabled, to read and modify that user's agents, memory and configuration.","summary":"Letta's REST API takes the acting tenant from a client-supplied user_id HTTP header (get_headers in letta/server/rest_api/dependencies.py) and never checks it against a credential. LETTA_SERVER_SECURE only adds one shared password, so any caller who has it, or anyone at all when secure mode is off, can read and modify another tenant's agents, memory and configuration by setting user_id. Affected: through 0.16.8. No fixed version has been published.","severity":"high","cvss":8.6,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"letta","fixed":[],"affected":"<= 0.16.8","ecosystem":"pypi"}],"ecosystems":[],"tags":["ai-tooling","auth-bypass","letta","multi-tenant","self-hosted"],"not_affected_if":["api-not-exposed","single-tenant","single-user-deployment","version-above-0.16.8"],"how_to_check":"Run a self-hosted Letta server at <= 0.16.8 (docker image letta/letta tag, or pip show letta on the server host). Multi-tenant exposure: with the API reachable, send a request with header 'user_id: user-<other tenant id>' and see whether you get that tenant's agents. Check whether your gateway forwards a client-supplied user_id header to Letta.","fix":"No fixed version published by the maintainer as of 2026-10-23 (GitHub release latest is 0.16.8; Docker Hub 0.34.18 not confirmed as a fix). Mitigate: have the gateway or reverse proxy strip any client user_id header and set it itself from authenticated identity; do not expose the API to untrusted callers; do not rely on Letta for tenant isolation (run one instance per tenant); set LETTA_SERVER_SECURE=true and rotate the shared password. Recheck the letta-ai/letta releases.","status":"open","published_at":"2026-10-20T01:17:20+00:00","first_seen_at":"2026-10-23T21:57:19+00:00","triaged_at":"2026-10-23T22:39:45+00:00","updated_at":"2026-10-23T22:42:05+00:00","category":"ai-tooling","confidence":0.8,"triage":{"at":"2026-10-23T22:39:45Z","model":"claude-haiku-5-5","output":{"fix":"unknown","reach":"network","title":"Letta: user_id header lets API callers impersonate other tenants","impact":"high","summary":"Letta through 0.16.8 trusts a self-asserted user_id HTTP header, so any API caller can act as another user. An attacker can read and modify that user's agents, memory and configuration, even when LETTA_SERVER_SECURE is enabled.","category":"ai-tooling","who_cares":["letta","self-hosted","multi-tenant"],"confidence":0.6,"needs_auth":"yes","worst_case":"attacker reads and changes another tenant's agents, memory and config","analyst_note":"Confirm the fixed version after 0.16.8 and whether the needs_auth value holds: the description says API callers, which may mean any valid key or no key at all. Check the NVD entry and the Letta release notes.","how_to_check":"unknown","needs_analyst":true,"not_affected_if":["version-above-0.16.8","single-user-deployment"],"user_interaction":"no","needs_special_setup":"no","severity_if_unknown":"high"},"cost_usd":0.000479,"input_tokens":2924,"output_tokens":374,"severity_before":"high"},"analyst_status":"done","analyst_note":"Confirm the fixed version after 0.16.8 and whether the needs_auth value holds: the description says API callers, which may mean any valid key or no key at all. Check the NVD entry and the Letta release notes.","search":"'-2026':12A,15A '-77937':13A,16A '0.16.8':99B,108C 'act':37B 'add':63B 'affect':97B 'agent':89B,155C 'ai':19B 'ai-tool':18B 'allow':115C 'anoth':86B,138C 'anyon':74B 'api':6A,34B,116C 'assert':127C 'attack':132C 'auth':22B 'auth-bypass':21B 'authent':111C 'bypass':23B,112C 'caller':7A,69B,117C 'check':54B 'client':42B 'client-suppli':41B 'configur':92B,158C 'contain':109C 'credenti':58B 'cve':11A,14A 'enabl':147C 'even':142C 'fix':101B 'get':48B 'header':4A,47B,49B,131C 'host':30B 'http':46B,130C 'id':3A,45B,96B,129C,136C,141C 'imperson':8A,119C 'let':5A 'letta':1A,17A,24B,31B,59B,106C,144C 'letta/server/rest_api/dependencies.py':51B 'memori':90B,156C 'mode':79B 'modifi':85B,151C 'multi':26B 'multi-ten':25B 'never':53B 'one':64B 'password':66B 'publish':105B 'read':83B,149C 'rest':33B 'secur':61B,78B,146C 'self':29B,126C 'self-assert':125C 'self-host':28B 'server':60B,145C 'set':94B,134C 'share':65B 'suppli':43B,123C 'take':35B 'tenant':10A,27B,38B,87B,139C 'tool':20B 'user':2A,44B,95B,121C,128C,135C,153C 'version':102B 'vulner':113C","nicknames":[],"mitigations":[],"who_affected":null,"tier":"B","verified":{},"analyst_revisit_at":null,"first_public_at":"2026-10-20T01:17:20+00:00","kev":null,"cvss_vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","cvss_by":"disclosure@vulncheck.com","poc_count":0,"sources":[{"source":"nvd","external_id":"CVE-2026-77937","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-77937","severity":null,"published_at":"2026-10-20T01:17:20+00:00","modified_at":"2026-10-20T20:11:29+00:00","first_seen_at":"2026-10-23T21:57:19+00:00","fetched_at":"2026-10-23T22:28:57+00:00","note":null},{"source":"analyst","external_id":"CVE-2026-77937:280","url":null,"severity":null,"published_at":"2026-10-23T22:42:05+00:00","modified_at":"2026-10-23T22:42:05+00:00","first_seen_at":"2026-10-23T22:42:05+00:00","fetched_at":"2026-10-23T22:42:05+00:00","note":"Read Lasso and VulnCheck advisories and the dependencies.py source. No vendor fix named: affected is 'through 0.16.8', GitHub release still 0.16.8, a Docker Hub 0.34.18 is not stated as a fix (secondary blog only). Auth: needs a valid caller (CVSS PR:L); with LETTA_SERVER_SECURE only a shared admin secret exists, so any holder of it can pick any tenant by user_id. With secure mode off (default compose) no key at all is needed (see sibling CVE-2026-77936). No PoC or exploitation reported; not in KEV. Note PyPI 'letta' is now the Letta Code CLI, not the server."}],"documents":[{"id":1566,"url":"https://www.lasso.security/vulnerability-database/cve-2026-77937","title":"Lasso Security: CVE-2026-77937 Cross-Tenant Impersonation via Self-Asserted user_id Header","kind":"advisory","source":"analyst","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":null},{"id":1567,"url":"https://www.vulncheck.com/advisories/letta-through-0.16.8-cross-tenant-impersonation-via-user-id-header","title":"VulnCheck: Letta through 0.16.8 Cross-Tenant Impersonation via user_id Header","kind":"advisory","source":"analyst","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":null},{"id":1568,"url":"https://github.com/letta-ai/letta/blob/1131535716e8a31c9a437f8695e25ac98f203a24/letta/server/rest_api/dependencies.py","title":"letta dependencies.py: get_headers takes actor_id from user_id header","kind":"other","source":"analyst","text":null,"published_at":null,"relation":"describes","confidence":null,"note":null},{"id":1569,"url":"https://xuanyuan.cloud/blog/letta-cve-2026-77936-77937-security-advisory","title":"Xuanyuan: Letta CVE-2026-77936 / 77937 advisory (no fixed tag; Docker Hub 0.34.18 not stated as fix)","kind":"blog","source":"analyst","text":null,"published_at":null,"relation":"mentions","confidence":null,"note":null}],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}