CVE-2026-90961 Overview
CVE-2026-90961 is an authentication bypass vulnerability in the LdapAuth and LinOTPAuth plugins for the Malware Information Sharing Platform (MISP). Both plugins replace CakePHP's FormAuthenticate class but omit the _checkFields() guard that validates credentials as non-empty strings. An unauthenticated attacker who knows any valid user email address can bind to the directory with an empty password, exploiting the RFC 4513 unauthenticated bind behavior. Successful exploitation grants full privileges of the impersonated account, including administrative access to threat intelligence data. Versions ≤2.5.45 are affected.
Critical Impact
Remote, unauthenticated attackers can log in as any known MISP user, including administrators, when LdapAuth or LinOTPAuth is enabled.
Affected Products
- MISP versions ≤2.5.45 with the LdapAuth plugin enabled
- MISP versions ≤2.5.45 with the LinOTPAuth plugin enabled
- MISP deployments using auto-provisioned LDAP accounts that later fall back to mixed authentication
Discovery Timeline
- 2026-09-14 - CVE-2026-90961 published to NVD
- 2026-09-16 - Last updated in NVD database
Technical Details for CVE-2026-90961
Vulnerability Analysis
The vulnerability originates in two custom authentication components: LdapAuthenticate and LinOTPAuthenticate. Both classes replace CakePHP's FormAuthenticate rather than extending it. They read email and password from the login request and pass them directly to downstream authentication logic without validating type or non-emptiness.
In the LDAP authenticator, an empty or null password reaches ldap_bind(). RFC 4513 section 5.1.2 defines a bind with a valid Distinguished Name (DN) and empty password as an unauthenticated bind. Many directory servers respond with success. An attacker who knows any valid directory email address authenticates as that user without a password.
The LinOTP authenticator suffers the same missing guard. Non-string credentials are concatenated into the LinOTP verification request, and the mixed-authentication branch accepts an empty password against a stored hash of the empty string. A secondary flaw compounds the issue: auto-provisioned users receive an empty password that bypasses validation on save, producing a stored hash of the empty string that later verifies against empty input.
Root Cause
The root cause is improper input validation [CWE-20]. Both plugins skip the _checkFields() guard from FormAuthenticate, allowing empty strings, null, false, and arrays to flow into ldap_bind(), _findUser(), and LinOTP request construction.
Attack Vector
Exploitation requires network access to the MISP login endpoint and knowledge of one valid email address. The attacker submits a login request containing a valid email and an empty or non-string password. The LDAP bind succeeds as an unauthenticated bind, and MISP grants a session with the impersonated user's privileges.
$userFields = $request->data['User'];
- $email = $userFields['email'];
- $password = $userFields['password'];
+ $email = isset($userFields['email']) ? $userFields['email'] : '';
+ $password = isset($userFields['password']) ? $userFields['password'] : '';
+
+ // This class replaces FormAuthenticate rather than extending it, so it has to
+ // repeat that class' _checkFields() guard: both credentials must be non-empty
+ // strings.
+ //
+ // RFC 4513 section 5.1.2: a bind request carrying a valid DN and an empty
+ // password is an unauthenticated bind, and many directories answer it with
+ // success. An empty password reaching ldap_bind() below would therefore
+ // authenticate anyone who knows a user's email address.
+ if (!is_string($email) || $email === '' || !is_string($password) || $password === '') {
+ CakeLog::error("[LdapAuth] Rejected login attempt with a missing or invalid email or password.");
+ return false;
+ }
Source: MISP security patch commit 0ee058548
Detection Methods for CVE-2026-90961
Indicators of Compromise
- Successful MISP login events with no corresponding LDAP bind password in directory server logs.
- Directory server audit logs showing bind operations with empty userPassword values.
- MISP audit_logs entries showing session creation for administrative accounts from unfamiliar source IPs.
- Unexpected data exports or API tokens generated by accounts that rarely log in interactively.
Detection Strategies
- Correlate MISP application login events with LDAP directory bind logs to identify sessions produced by unauthenticated binds.
- Search MISP logs for the patched error string [LdapAuth] Rejected login attempt or [LinOTPAuth] Rejected login attempt after applying the fix to identify probing attempts.
- Alert on directory server responses to bind requests where the password field length is zero.
Monitoring Recommendations
- Enable verbose logging on LDAP directory servers to capture bind DN and password presence for every attempt.
- Forward MISP application logs and directory logs to a central analytics platform for correlation.
- Monitor authentication anomalies such as new source geographies, unusual user-agents, or off-hours administrator logins.
How to Mitigate CVE-2026-90961
Immediate Actions Required
- Upgrade MISP to the version containing commit 0ee058548 or later immediately.
- Audit MISP users table for accounts with empty or default password hashes and reset them.
- Rotate API keys and session tokens for any accounts that may have been impersonated.
- Review recent MISP audit logs for suspicious logins during the exposure window.
Patch Information
The fix is available in the MISP repository via commit 0ee058548, which adds is_string() and non-empty checks to both LdapAuthenticate.php and LinOTPAuthenticate.php before credentials reach ldap_bind() or LinOTP request construction. See the MISP GitHub commit for full patch details.
Workarounds
- Disable the LdapAuth and LinOTPAuth plugins until the patch is applied and switch to FormAuthenticate with strong local passwords.
- Configure the upstream LDAP directory to reject unauthenticated binds by setting disallow bind_anon in OpenLDAP or the equivalent directive in Active Directory.
- Place MISP behind a reverse proxy that enforces client certificate authentication or IP allowlisting for the login endpoint.
# OpenLDAP: reject unauthenticated binds in slapd.conf
disallow bind_anon
require authc
# Verify no MISP users have an empty-string password hash
mysql -e "SELECT id, email FROM misp.users WHERE password = SHA2('', 256) OR password = '';"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

