CVE-2026-42849: How One Link Can Take Over an Authentik Session
Found during a customer pentest: CVE-2026-42849 lets attackers take over an Authentik session via a crafted link. Finding, impact, and patch.

One OAuth URL Is Enough
On May 12, 2026, the Authentik team published CVE-2026-42849. We came across the bug during a penetration test against a customer's high-security infrastructure and reported it on April 24, 2026 to Authentik as a Reflected Cross-Site Scripting flaw in the Simple Flow Executor. Developing our own vulnerabilities in deployed software, rather than limiting ourselves to ticking off documented CVE lists, is part of our standard approach. The official CVSS score is 9.3 (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N). Affected versions are Authentik 2026.2.2 and earlier, as well as 2025.12.4 and earlier. The fix is shipped in 2026.2.3 and 2025.12.5.
In practice that means: anyone running an active Authentik tenant with an OAuth2 provider who has not updated to the patched version is sitting on an exploitable XSS on their own Single Sign-On origin. An authenticated user clicks a crafted OAuth URL, and the Authentik server reflects the injected payload straight into the browser. The code executes inside the Authentik origin context, with access to session cookies, locally stored tokens, and every backend API the user is allowed to call.
This article walks through the sink, both attack vectors, the prerequisites for exploitation, and the consequences for SSO operators who cannot patch immediately.
Anatomy of the Sink
The Simple Flow Executor is a second, lightweight rendering variant of the Authentik login flows. Authentik uses it when the browser cannot execute the modern JavaScript bundle, or when the caller appends ?sfe to the flow URL. The SFE is written in JavaScript and lives at web/packages/sfe/src/index.ts.
The relevant method is AutosubmitStage.render. It builds an HTML form via template-literal concatenation and writes the result to the DOM without any sanitization. The excerpt below is shortened compared to the original (brand logo, title heading, and spinner removed); the XSS-relevant interpolation points are unchanged:
render() {
this.html(`
<form id="autosubmit-form" action="${this.challenge.url}" method="POST">
${Object.entries(this.challenge.attrs).map(([key, value]) =>
`<input type="hidden" name="${key}" value="${value}" />`
)}
</form>`);
$("#autosubmit-form").submit();
}
html(html: string) {
this.executor.container.innerHTML = html;
}
Both this.challenge.url and every value in this.challenge.attrs are interpolated unescaped into an HTML attribute. As soon as one of those values contains a double quote, it breaks out of the attribute context. The sink is container.innerHTML. The jQuery submit call after the assignment uses the rendered form, but by that point the browser has already parsed the injected DOM content and triggered side effects like <img src=...>.
The Authentik team names the root cause in the advisory itself: the SFE was written to keep compatibility with legacy browsers and relies on jQuery without proper sanitization of input values.
Vector 1: the state Parameter
The OAuth2 flow accepts a state parameter that the client and the authorization server pass between each other for CSRF protection. Authentik writes the value straight into AutosubmitChallenge.attrs["state"]. In the SFE it ends up inside the value attribute of a hidden input.
An attacker builds the following URL and sends it to a logged-in victim:
https://authentik.example.com/application/o/authorize/?
client_id=<valid_id>
&redirect_uri=<registered_uri>
&response_type=code
&response_mode=form_post
&state="><img src="https://attacker.example/xss"><input name="z" value="
&sfe
The appended &sfe forces Authentik into the Simple Flow Executor. The state value breaks out of the value="..." attribute, closes the input tag, injects an <img> with an attacker-controlled source, and opens a harmless input tag so that the rest of the template remains valid HTML.
The effect: as soon as the victim's browser runs the innerHTML assignment, it parses the injected <img> tag and fires a cross-origin request to the attacker domain. The request headers contain Origin: https://authentik.example.com. This proves that the code executed inside the Authentik origin context, with access to cookies, locally stored tokens, and the authenticated session material.
The only tenant prerequisite is that at least one OAuth2 provider with a bound application exists, and that the authorization flow remains on the default default-provider-authorization-implicit-consent. The attacker needs a valid client_id and a registered redirect_uri. Both are obtainable from public sources or passive observation of legitimate OAuth flows. .well-known/openid-configuration does not expose them, but JS bundles of bound applications, error messages, and setup documentation usually do.
Vector 2: the redirect_uri Parameter
The second path uses the redirect_uri. Authentik writes it into AutosubmitChallenge.url, which in the SFE becomes the action attribute of the form. Breaking out of action="..." is structurally identical to the state vector.
The prerequisite is an OAuth2 provider that uses matching_mode: regex for the redirect_uri with a permissive pattern. The worst case is .*. In real-world deployments we also see patterns like https?://.* or https://example\.com/.*. As soon as the regex permits an attacker-controlled string, the redirect_uri vector is open. Under matching_mode: strict this path is blocked, but the state vector remains exploitable.
Anyone familiar with CVE-2024-21637 will recognize the anti-pattern. The advice back then was already to avoid regex matching unless strictly necessary. Third-party setup guides and migrations from older OIDC stacks continue to carry the pattern into production tenants.
Impact
The code runs in the victim's browser on the Authentik origin. Four consequences follow:
- Session hijacking via the
authentik_sessioncookie. Authentik setsHttpOnly=Trueby default. Anyone who has overridden this default is directly exposed; anyone who has not is still reachable through CSRF-style API calls riding on the active session. - Token exfiltration from
localStorageon the Authentik domain, if the application stores material there. - CSRF-capable API calls against any Authentik endpoint with the victim's identity.
- Tenant takeover if the victim holds a privileged role.
In MITRE ATT&CK terms, the attack path maps to T1539 Steal Web Session Cookie. The technique describes how an authenticated browser context is taken over through session cookies, without requiring the attacker to repeat the login flow.
The attacker needs no account on the tenant and no admin access. They need a working link, a valid client_id, a logged-in victim, and one second. The OWASP Top 10 entry A03:2021 Injection explains why an unsanitized innerHTML assignment continues to land in production code despite all modern framework conventions: legacy paths and compatibility code are audited far less often than the main render pipelines.
Patch and Mitigation
The primary fix recommended by the Authentik team is the upgrade to 2026.2.3 or 2025.12.5. The official Authentik releases contain the patch and do not break any existing configuration. Authentik also documents the incident in its own CVE entry for CVE-2026-42849, including patch guidance, affected versions, and workarounds for tenants that cannot upgrade immediately.
If patching today is not possible for operational reasons, three short-term hardening steps are available. The first is switching from matching_mode: regex to matching_mode: strict on every OAuth2 provider, with the exact callback URLs spelled out. This closes the redirect_uri vector completely.
The second step is disabling the Simple Flow Executor at the reverse proxy. An nginx snippet that rejects every request carrying ?sfe or the corresponding cookie does break legacy browser support, but closes both vectors. For most enterprise tenants that trade-off is acceptable:
if ($arg_sfe) { return 400; }
if ($http_cookie ~* "sfe=") { return 400; }
The third step is a strict Content Security Policy on the flow routes /if/flow/*. The OWASP Cross Site Scripting Prevention Cheat Sheet recommends a restrictive policy as defense in depth:
Content-Security-Policy: default-src 'self'; script-src 'self'; img-src 'self'; object-src 'none'
The img-src 'self' directive is essential. The exfiltration vector in both PoCs runs through <img src=...> without any script execution. A CSP that only constrains script-src will not block this path.
Lessons for SSO Deployments
The incident is small in code change and large in lesson. First: legacy render paths deserve their own audit. Hardening the main path of an application leaves a second, older render variant that becomes active under special conditions and has significantly fewer protective layers. The SFE in Authentik is one example; similar paths exist in many identity stacks.
Second: innerHTML with string interpolation is no longer an acceptable pattern in 2026. Modern UI frameworks offer DOM API constructors that eliminate the problem structurally. Anyone building their own components should make document.createElement plus appendChild the default, and only allow string templates for plain text via textContent.
Third: regex redirect_uri is a self-inflicted attack surface. Authentik has documented this clearly since the patch wave around CVE-2024-21637, yet permissive patterns continue to appear in production configurations. SSO operators should keep an inventory of all OAuth2 providers and audit the matching_mode on every provider regularly.
Conclusion
CVE-2026-42849 is a textbook Reflected XSS, sitting in a lean, easy-to-overlook legacy path of an otherwise clean IAM product. The sink is a single unsanitized innerHTML assignment, the attack needs no admin access and no tenant manipulation, and the impact is session takeover inside the SSO trust context. Authentik operators should upgrade today to 2026.2.3 or 2025.12.5. Anyone who cannot patch should disable the SFE at the reverse proxy and apply a restrictive CSP on the flow routes. And anyone planning an SSO audit should treat legacy render paths, innerHTML sinks, and permissive redirect_uri regexes as three separate items on the checklist. A targeted penetration test against the login flows shows whether the mitigation in your environment actually holds.