CVE-2025-64521
Executive Summary
CVE-2025-64521 is an authentication bypass vulnerability in authentik, an open-source Identity Provider. The flaw allows an attacker to authenticate using a deactivated service account when using OAuth2 authentication with client_id and client_secret. This bypasses the intended access control, potentially allowing unauthorized access to applications. The vulnerability affects versions prior to 2025.8.5 and 2025.10.2. The CVSS score is 4.8 (Medium), and the EPSS score is 0.0%, indicating low exploitation likelihood at this time. No public exploit code or PoC is available.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability is in the authentik application itself, not in a package manager (NPM, PyPI, Go, Ruby). However, organizations using authentik as a dependency in their identity infrastructure should treat this as a critical supply chain risk, as a compromised IdP can lead to cascading access breaches.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N
- Base Score: 4.8 (Medium)
- Attack Vector: Network (AV:N)
- Attack Complexity: Low (AC:L)
- Privileges Required: Low (PR:L) – requires valid client_id and client_secret
- User Interaction: None (UI:N)
- Scope: Unchanged (S:U)
- Confidentiality Impact: Low (C:L)
- Integrity Impact: Low (I:L)
- Availability Impact: None (A:N)
Threat Level: Medium. The vulnerability requires valid OAuth client credentials, but once obtained, an attacker can bypass account deactivation controls.
Deep Dive & Mechanics
The vulnerability lies in the OAuth2 provider authentication flow within authentik. When a client authenticates using client_id and client_secret, authentik creates a service account for that provider. In vulnerable versions, the authentication logic does not properly check the is_active status of this service account. This means that even if an administrator deactivates the service account (e.g., due to compromise or policy violation), the account can still be used to authenticate and obtain tokens.
The root cause is a missing or incorrect check in the authentication middleware or provider handler. The code likely validates the credentials but fails to verify the account's active status before issuing tokens.
Vulnerable vs. Patched Code
Vulnerable Code (Conceptual):
# In OAuth2 provider authentication handler
def authenticate(client_id, client_secret):
service_account = get_service_account(client_id)
if service_account and service_account.client_secret == client_secret:
# Missing check: if not service_account.is_active: raise AuthError
return generate_token(service_account)
raise AuthError("Invalid credentials")
Patched Code (Conceptual):
def authenticate(client_id, client_secret):
service_account = get_service_account(client_id)
if service_account and service_account.client_secret == client_secret:
if not service_account.is_active:
raise AuthError("Account deactivated")
return generate_token(service_account)
raise AuthError("Invalid credentials")
The patch adds a check for service_account.is_active before token generation.
Exploitation & Lab Setup
Red Team
Prerequisites:
- Valid OAuth2 client credentials (
client_idandclient_secret) for a deactivated service account. - Network access to the authentik instance.
Exploitation Steps:
- Obtain the
client_idandclient_secretfor a deactivated service account (e.g., via previous compromise, insider threat, or misconfiguration). - Initiate an OAuth2 token request to the authentik token endpoint:
curl -X POST https://authentik.example.com/application/o/token/ \ -d "grant_type=client_credentials" \ -d "client_id=DEACTIVATED_CLIENT_ID" \ -d "client_secret=DEACTIVATED_CLIENT_SECRET" - If successful, the response will contain an access token:
{ "access_token": "eyJhbGciOiJSUzI1NiIs...", "token_type": "Bearer", "expires_in": 3600 } - Use the token to access protected resources:
curl -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." https://protected-app.example.com/api/resource
Blue Team
Detection:
- Monitor for token requests using deactivated service accounts. Correlate with account status changes.
- Alert on successful token issuance for accounts with
is_active=False. - Review authentik audit logs for authentication events from deactivated accounts.
Hunting:
- Query authentik logs for
authenticationevents whereservice_account.is_activeisFalsebut the event succeeded. - Search for OAuth2 token requests with
client_idvalues that correspond to deactivated service accounts.
Lab Setup:
- Deploy authentik 2025.8.4 (vulnerable) using Docker:
docker run -d --name authentik -p 9000:9000 -p 9443:9443 \ -e AUTHENTIK_SECRET_KEY=testkey \ -e AUTHENTIK_POSTGRESQL__HOST=localhost \ -e AUTHENTIK_POSTGRESQL__USER=authentik \ -e AUTHENTIK_POSTGRESQL__NAME=authentik \ ghcr.io/goauthentik/server:2025.8.4 - Create an OAuth2 provider and service account.
- Deactivate the service account via the admin UI.
- Attempt to authenticate using the deactivated credentials.
Indicators of Compromise (IOCs)
- Network: OAuth2 token requests to
/application/o/token/withgrant_type=client_credentialsfor deactivated service accounts. - Logs: authentik audit log entries showing successful authentication for accounts with
is_active=False. - Token: JWT tokens issued for deactivated service accounts (check
suborclient_idclaim against account status). - File: No specific file-based IOCs.
Detection Engineering
YARA Rule
rule Detect_Authentik_Deactivated_Account_Auth {
meta:
description = "Detects authentik logs indicating authentication with a deactivated service account"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-64521"
strings:
$log1 = "authenticated" nocase
$log2 = "service_account" nocase
$log3 = "is_active=False" nocase
condition:
all of ($log*) and #log1 > 0
}
Sigma Rule
title: Authentik Deactivated Service Account Authentication
id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
status: experimental
description: Detects successful authentication using a deactivated service account in authentik
author: Valters IT
date: 2025-04-10
references:
- https://nvd.nist.gov/vuln/detail/CVE-2025-64521
logsource:
product: authentik
service: audit
detection:
selection:
event_type: "authentication"
service_account.is_active: false
result: "success"
condition: selection
falsepositives:
- Legitimate re-activation of account before authentication
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"CVE-2025-64521 - Authentik Deactivated Service Account Auth Bypass";
flow:to_server,established;
content:"POST"; http_method;
content:"/application/o/token/"; http_uri;
content:"grant_type=client_credentials"; http_client_body;
content:"client_id="; http_client_body;
content:"client_secret="; http_client_body;
sid:1000001;
rev:1;
reference:cve,2025-64521;
classtype:attempted-user;
priority:2;
)
Remediation & Mitigation
Immediate:
- Upgrade to authentik 2025.8.5 or 2025.10.2.
- If upgrade is not possible, apply the workaround: Add a policy to the application that explicitly checks if the service account is still valid and deny access if not.
Long-term:
- Implement regular audits of service account statuses.
- Enforce least privilege for OAuth client credentials.
- Monitor for authentication anomalies.
Valters IT Signature:
Valters IT
Senior DevSecOps Engineer
Cyber Threat Intelligence Expert