CVE-2025-8850
Executive Summary
CVE-2025-8850 is a security advisory affecting danny-avila/librechat version 0.7.9. The vulnerability is an insecure API design flaw in the 2-Factor Authentication (2FA) flow. Specifically, the backend endpoint /api/auth/2fa/disable does not properly validate the OTP or backup code before disabling 2FA. This allows an authenticated user to bypass the intended verification process and weaken their own account's security posture. While this does not lead to full account compromise, it undermines the integrity of the 2FA mechanism, making accounts more susceptible to subsequent attacks if the session is hijacked.
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 a Node.js application (LibreChat). The package is distributed via npm and GitHub. The insecure API design is a server-side logic flaw, not a dependency injection issue. However, the lack of a patch or advisory from the vendor increases supply chain risk for organizations using this software without proper code review or security controls.
CVSS Breakdown & Threat Level
- CVSS Score: 3.1 (Low)
- Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N
- Attack Vector: Network
- Attack Complexity: Low
- Privileges Required: Low (authenticated user)
- User Interaction: None
- Scope: Unchanged
- Confidentiality Impact: None
- Integrity Impact: Low (2FA can be disabled)
- Availability Impact: None
Threat Level: Low. The vulnerability requires authentication and only allows a user to weaken their own account's 2FA. It does not enable privilege escalation or data theft.
Deep Dive & Mechanics
The vulnerability lies in the backend API endpoint /api/auth/2fa/disable. In a secure implementation, disabling 2FA should require the user to provide a valid OTP (from their authenticator app) or a backup code to prove possession of the second factor. In LibreChat 0.7.9, the endpoint does not enforce this check. When an authenticated user sends a POST request to this endpoint, the server disables 2FA without verifying the OTP or backup code.
Root Cause: Missing authentication/authorization check on the disable action. The server trusts the session token but does not require re-verification of the second factor.
Attack Scenario:
- An attacker gains access to a user's session token (e.g., via XSS, session fixation, or physical access).
- The attacker sends a POST request to
/api/auth/2fa/disablewith the session cookie. - The server disables 2FA without requiring OTP.
- The attacker can now log in with just the password, bypassing 2FA.
Impact: While the attacker cannot directly compromise the account without the password, disabling 2FA reduces the security barrier. If the attacker also obtains the password (e.g., via phishing), they can now log in without the second factor.
Vulnerable vs. Patched Code
Vulnerable Code (librechat 0.7.9):
// routes/auth.js (hypothetical)
router.post('/api/auth/2fa/disable', authenticate, async (req, res) => {
// Missing OTP/backup code validation
await User.updateOne({ _id: req.user.id }, { twoFactorEnabled: false });
res.json({ success: true });
});
Patched Code (expected fix):
// routes/auth.js (patched)
router.post('/api/auth/2fa/disable', authenticate, async (req, res) => {
const { otp, backupCode } = req.body;
if (!otp && !backupCode) {
return res.status(400).json({ error: 'OTP or backup code required' });
}
// Validate OTP or backup code
const user = await User.findById(req.user.id);
if (otp) {
const isValid = speakeasy.totp.verify({ secret: user.twoFactorSecret, encoding: 'base32', token: otp });
if (!isValid) return res.status(401).json({ error: 'Invalid OTP' });
} else if (backupCode) {
if (!user.backupCodes.includes(backupCode)) return res.status(401).json({ error: 'Invalid backup code' });
// Remove used backup code
user.backupCodes = user.backupCodes.filter(code => code !== backupCode);
}
user.twoFactorEnabled = false;
await user.save();
res.json({ success: true });
});
Exploitation & Lab Setup
Red Team
Prerequisites:
- Access to a LibreChat instance (version 0.7.9)
- Valid user credentials (or session token)
Exploitation Steps:
- Log in to LibreChat and obtain a session cookie.
- Send a POST request to disable 2FA:
curl -X POST https://target.com/api/auth/2fa/disable \ -H "Cookie: connect.sid=s%3A...your_session..." \ -H "Content-Type: application/json" \ -d '{}' - Verify 2FA is disabled by checking the user profile or attempting to log in again.
Note: No public exploit code is available. This is a simple API call.
Blue Team
Detection:
- Monitor API logs for POST requests to
/api/auth/2fa/disablewithout accompanying OTP or backup code parameters. - Alert on multiple 2FA disable attempts from the same user in a short time window.
- Correlate with failed login attempts or session anomalies.
Hunting:
- Search for logs where
req.body.otpis undefined or empty for the disable endpoint. - Look for users who disable 2FA and then immediately change their password.
Indicators of Compromise (IOCs)
- Network: POST requests to
/api/auth/2fa/disablewith empty or missingotpandbackupCodefields. - Logs: Server logs showing
User.updateOnefortwoFactorEnabled: falsewithout prior OTP validation. - User Behavior: Account with 2FA disabled without a corresponding OTP verification event.
Detection Engineering
YARA Rule
rule Detect_LibreChat_2FA_Bypass {
meta:
description = "Detects insecure 2FA disable API call in LibreChat logs"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-8850"
strings:
$api_path = "/api/auth/2fa/disable"
$missing_otp = "otp" nocase
$missing_backup = "backupCode" nocase
condition:
$api_path and not ($missing_otp or $missing_backup)
}
Sigma Rule
title: LibreChat 2FA Disable Without OTP
id: 8a4b3c2d-1e5f-4a7b-9c8d-0e1f2a3b4c5d
status: experimental
description: Detects attempts to disable 2FA in LibreChat without providing OTP or backup code
author: Valters IT
date: 2025-04-10
logsource:
category: application
product: librechat
detection:
selection:
http.method: POST
http.url: "/api/auth/2fa/disable"
filter:
- http.body|contains: "otp"
- http.body|contains: "backupCode"
condition: selection and not filter
falsepositives:
- Legitimate API calls with missing fields due to client error
level: medium
Suricata Rule
alert http any any -> any any (msg:"CVE-2025-8850 LibreChat 2FA Disable Bypass"; flow:to_server; http.method; content:"POST"; http.uri; content:"/api/auth/2fa/disable"; http.request_body; content:!"otp"; content:!"backupCode"; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable the 2FA disable endpoint until a patch is available, or implement a temporary middleware that requires OTP validation.
- Monitor logs for unauthorized 2FA disable attempts.
- Enforce session timeout and re-authentication for sensitive actions.
Long-term Fix:
- Update to a patched version of LibreChat once released.
- Implement server-side validation for all 2FA-related endpoints.
- Conduct a security audit of all API endpoints for missing authorization checks.
Workaround:
- Use a Web Application Firewall (WAF) to block requests to
/api/auth/2fa/disablethat do not containotporbackupCodeparameters.
Valters IT
Securing Digital Frontiers
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.