CVE-2026-90979: Apache Karaf: LDAP filter injection in JAAS LDAP login modules
LDAPCache and LDAPBackingEngine build LDAP search filters for user lookup and role lookup by textually substituting the placeholders %u, %dn, and %fqdn (drawn from the login name, the resolved user DN, and its fully qualified namespace form) into administrator-configured filter templates (userFilter, roleFilter). Before the fix, the only sanitization applied to the substituted value was double backslashed:
filter = filter.replaceAll(Pattern.quote("%u"), Matcher.quoteReplacement(user));
filter = filter.replace("\\", "\\\\");
This does not escape the other characters RFC 4515 requires escaping in an LDAP search filter: , (, ), and NUL. A login name containing any of these can change the structure of the resulting filter rather than being matched as a literal value (e.g. a crafted username can turn an equality match into a wildcard match, or close/reopen filter clauses), widening what the search returns and potentially causing a login or role lookup to match an LDAP entry other than the intended one, over-granting roles, and depending on deployment-specific filter templates, potentially affecting which account a login resolved to.
It's not exploitable through every entry points: LDAPLoginModule and LDAPPubkeyLoginModule both called Util.doRFC2254Encoding() (correct RFC 4515 escaping) on the login name before handing it to LDAPCache, which masked the missing escaping in LDAPCache for those two call paths. Using LDAPCache directly (bypassing the login modules) does not reproduce through the normal LDAPLoginModule/LDAPPubkeyLoginModule authentication flow for this reason. It does reproduce through two other call paths that reach LDAPCache/LDAPBackingEngine without any prior escaping:
GSSAPILdapLoginModule passes the NameCallback name straight through, unescaped. LDAPBackingEngine (listRoles) passes principal.getName() straight through, unescaped.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Compensating control
Apply RFC 4515 escaping to login names, resolved user DNs, and fully qualified namespace values before substituting them for %u, %dn, and %fqdn in LDAPCache and LDAPBackingEngine filter templates; use Util.doRFC2254Encoding() so *, (, ), backslash, and NUL cannot alter the LDAP search filter structure.
Event History
Frequently Asked Questions
What does an attacker need to control to exploit this issue?
The attacker needs to supply a login name containing LDAP filter metacharacters such as *, (, ), or NUL. Exploitation also depends on that value reaching an affected LDAP lookup through configured userFilter or roleFilter templates.
Which configurations should be reviewed first?
Review LDAPCache and LDAPBackingEngine configurations that use userFilter or roleFilter templates with the %u, %dn, or %fqdn placeholders. These values were substituted into LDAP filters without escaping all characters required by RFC 4515.
What can a successful exploit change?
A crafted value can alter the LDAP filter structure, such as turning an equality comparison into a wildcard match or changing filter clauses. This can cause user or role lookups to match an unintended LDAP entry, potentially granting excess roles or, depending on the configured templates, resolving a login to a different account.
Are all LDAP authentication entry points affected?
No. The available information states that the issue is not exploitable through every entry point, but does not identify which entry points are affected or excluded.