CVE-2025-64708
Executive Summary
CVE-2025-64708 is a security advisory affecting Authentik, an open-source Identity Provider. The vulnerability lies in the handling of expired invitations. Prior to versions 2025.8.5 and 2025.10.2, invitations were considered valid regardless of their expiration status, relying solely on background tasks to clean up expired ones. This creates a window of opportunity where an attacker can use an expired invitation to gain unauthorized access. The cleanup process runs every 5 minutes, but can be delayed further under heavy load. The CVSS score is 5.8 (Medium), indicating a moderate risk of unauthorized access.
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
Authentik is a Python-based application distributed via Docker images and PyPI. The vulnerability is in the core application logic, not in a dependency. However, organizations using Authentik should verify the integrity of their deployment images and ensure they are sourced from official repositories.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N
- Base Score: 5.8 (Medium)
- Attack Vector: Network (AV:N) – The vulnerability can be exploited remotely.
- Attack Complexity: Low (AC:L) – No special conditions are required.
- Privileges Required: None (PR:N) – No authentication is needed.
- User Interaction: None (UI:N) – The victim does not need to perform any action.
- Scope: Unchanged (S:U) – The exploit cannot affect other components.
- Confidentiality Impact: Low (C:L) – Limited information disclosure.
- Integrity Impact: Low (I:L) – Limited data modification.
- Availability Impact: None (A:N) – No denial of service.
Threat Level: Medium. The vulnerability allows an attacker to use an expired invitation to potentially gain access to resources that should be protected. The impact is limited by the fact that the invitation itself must have been previously valid and the attacker must have obtained it.
Deep Dive & Mechanics
The vulnerability stems from a logic flaw in the invitation validation process. In Authentik, invitations are used to allow users to self-register or access specific flows. Each invitation has an expiration timestamp. The intended behavior is that once an invitation expires, it should be rejected.
However, in vulnerable versions, the code does not check the expiration timestamp at the time of use. Instead, it relies on a background task (Celery beat) that runs every 5 minutes to delete expired invitations from the database. This means that for up to 5 minutes (or longer under load), an expired invitation remains in the database and is considered valid by the application.
The attack scenario is as follows:
- An attacker obtains a valid invitation (e.g., through social engineering, phishing, or by intercepting an email).
- The invitation expires.
- The attacker uses the expired invitation within the cleanup window (up to 5 minutes or more).
- The application accepts the invitation because it still exists in the database and the expiration check is not performed at the point of use.
The fix in versions 2025.8.5 and 2025.10.2 adds an explicit expiration check during the invitation validation stage, ensuring that expired invitations are rejected immediately regardless of their presence in the database.
Vulnerable vs. Patched Code
Vulnerable Code (Conceptual):
# In the invitation validation stage
def validate_invitation(invitation_id):
invitation = Invitation.objects.get(id=invitation_id)
# No expiration check here
return invitation
Patched Code (Conceptual):
from django.utils import timezone
def validate_invitation(invitation_id):
invitation = Invitation.objects.get(id=invitation_id)
if invitation.expires_at and invitation.expires_at < timezone.now():
raise ValidationError("Invitation has expired")
return invitation
The patched version adds a check against the current time. If the invitation has an expiration date and it is in the past, the validation fails.
Exploitation & Lab Setup
Red Team
Prerequisites:
- A running instance of Authentik (vulnerable version < 2025.8.5 or < 2025.10.2).
- A valid invitation token (e.g., from an email or a shared link).
- Knowledge of the invitation flow endpoint.
Exploitation Steps:
- Obtain a valid invitation token (e.g.,
INV-12345). - Wait for the invitation to expire (or manipulate the system clock if in a lab).
- Send a request to the invitation validation endpoint with the expired token:
curl -X POST https://authentik.example.com/api/v3/stages/invitation/validate/ \ -H "Content-Type: application/json" \ -d '{"invitation": "INV-12345"}' - If the response is successful (HTTP 200), the vulnerability is confirmed.
Note: No public exploit code is available for this CVE.
Blue Team
Detection:
- Monitor for repeated use of the same invitation token, especially after its expiration time.
- Look for anomalies in the
authentik_invitationtable (e.g., invitations used after theirexpires_attimestamp). - Enable detailed logging for the invitation stage.
Hunting Query (SQL):
SELECT * FROM authentik_invitation
WHERE used = TRUE
AND expires_at < NOW()
AND used_at > expires_at;
Lab Setup:
- Deploy a vulnerable version of Authentik using Docker:
docker run -d --name authentik-vuln \ -e AUTHENTIK_SECRET_KEY=test \ -e AUTHENTIK_POSTGRESQL__HOST=db \ -e AUTHENTIK_POSTGRESQL__USER=authentik \ -e AUTHENTIK_POSTGRESQL__PASSWORD=test \ -e AUTHENTIK_POSTGRESQL__NAME=authentik \ ghcr.io/goauthentik/server:2025.8.4 - Create an invitation with a short expiration (e.g., 1 minute) and test the exploit.
Indicators of Compromise (IOCs)
- Network: Repeated POST requests to
/api/v3/stages/invitation/validate/with the same invitation token. - Logs:
authentik_stage_invitationlog entries showing successful validation of an invitation that has anexpires_attimestamp in the past. - Database: Rows in
authentik_invitationwhereused = TRUEandexpires_at < used_at.
Detection Engineering
YARA Rule
rule CVE_2025_64708_Authentik_Expired_Invitation {
meta:
description = "Detects expired invitation usage in Authentik logs"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-64708"
strings:
$s1 = "invitation" nocase
$s2 = "validate" nocase
$s3 = "expired" nocase
condition:
all of them
}
Sigma Rule
title: Authentik Expired Invitation Usage
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects successful validation of an expired invitation in Authentik
references:
- https://nvd.nist.gov/vuln/detail/CVE-2025-64708
tags:
- attack.initial_access
- cve.2025.64708
logsource:
product: authentik
service: stage_invitation
detection:
selection:
event: "invitation_validated"
invitation_expires_at|lt: now()
condition: selection
falsepositives:
- Legitimate use of an invitation that was just expired (within the cleanup window)
level: medium
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-64708 Authentik Expired Invitation Attempt"; flow:to_server; content:"POST"; http_method; content:"/api/v3/stages/invitation/validate/"; http_uri; content:"invitation"; http_client_body; pcre:"/\"invitation\":\s*\"[^\"]+\"/"; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Upgrade to Authentik version 2025.8.5 or 2025.10.2.
- If upgrade is not possible, apply the workaround: Create a policy that explicitly checks whether the invitation is still valid, and bind it to the invitation stage on the invitation flow, denying access if the invitation is not valid.
Long-term Measures:
- Implement real-time validation of invitation expiration rather than relying on background cleanup.
- Monitor for any unusual invitation usage patterns.
- Regularly review and rotate invitation tokens.
Valters IT Signature: This report was generated by Valters IT DevSecOps & CTI Expert System. For questions, contact security@valters-it.com.