What it is#
LDAP directories use structured filters and distinguished names to find and manage entries. LDAP injection occurs when an application concatenates untrusted input into that syntax.
Special characters can change a filter's logic, add wildcards, terminate one expression, or alter a distinguished name. Filter escaping and distinguished-name escaping are different operations; using the wrong one can leave the query vulnerable.
LDAP is often connected to authentication and enterprise identity, so a small query mistake can have broad organizational impact.
Why it matters#
- Bypass an application login that incorrectly uses a directory search as authentication.
- Broaden a lookup and enumerate users, groups, email addresses, or organizational data.
- Retrieve another user's record or attributes.
- Modify or delete unintended directory entries when write operations are constructed unsafely.
- Enumerate privileged groups and service accounts for further attacks.
- Cause expensive wildcard searches and directory-service degradation.
Medium for constrained information disclosure. High to critical when injection bypasses authentication, exposes sensitive directory attributes, or permits modification of identity and group records. Actual severity depends on context: who is affected, what data or actions are reachable, and existing controls.
Examples#
// Vulnerable: username becomes LDAP filter syntax.
String filter = "(&(objectClass=person)(uid=" + username + "))";
NamingEnumeration<SearchResult> results = context.search(
"ou=people,dc=example,dc=com", filter, controls);
// Fixed: JNDI substitutes and escapes the filter argument as a value.
String filter = "(&(objectClass=person)(uid={0}))";
Object[] arguments = { username };
NamingEnumeration<SearchResult> results = context.search(
"ou=people,dc=example,dc=com", filter, arguments, controls);
Authentication should bind as the located user or use the identity provider's supported authentication flow. A successful search for a username and attacker-controlled password is not, by itself, a safe authentication design.
How to fix it#
1. Use parameterized directory APIs. Pass values separately from the filter or use a maintained LDAP query builder that performs context-appropriate encoding.
2. Distinguish filter values from distinguished names. Use RFC 4515 filter escaping for filter values and RFC 4514 handling for distinguished names. Do not reuse a generic HTML, URL, or SQL escape function.
3. Allowlist expected input. Usernames, group identifiers, and attribute names should follow a narrow business grammar and length. Attribute names and operators should be server controlled.
4. Keep the search base fixed. Do not let users supply a base DN, scope, attribute list, sort key, or raw filter fragment unless selected through a strict server-owned mapping.
5. Use least-privilege bind accounts. Search-only applications should not be able to modify the directory or read sensitive attributes. Separate read and administrative identities.
6. Limit searches. Set result count, time, scope, page size, and returned attributes. Avoid broad subtree searches when a narrower base is sufficient.
7. Use supported authentication architecture. Prefer a centralized identity provider and standard protocols rather than custom password checking against directory searches.
8. Return generic authentication failures. Do not reveal whether a username exists, which filter failed, or internal directory structure.
9. Log safely. Record operation type, result count, duration, and requesting identity without logging passwords or raw attacker-controlled filters.
How to test for it#
- Search code for LDAP filters and distinguished names built through concatenation, interpolation, or string formatting.
- Inventory login, user lookup, group search, address-book, synchronization, and administrative directory features.
- With a dedicated test directory, submit LDAP special characters and wildcard-like input and confirm they are treated as literal values or rejected.
- Verify a lookup for one synthetic user cannot broaden to other test entries.
- Confirm search base, scope, returned attributes, result count, and timeout are fixed by the server.
- Test read and write bind accounts to verify least privilege without modifying production identity records.
- Review logs and error messages for passwords, raw filters, directory paths, and user-enumeration differences.
- Add unit tests covering encoding and integration tests against the same LDAP server implementation used in production.
References#
- CWE-90: Improper Neutralization of Special Elements used in an LDAP Query ↗ (opens in a new tab)cwe.mitre.org
- OWASP LDAP Injection Prevention Cheat Sheet ↗ (opens in a new tab)cheatsheetseries.owasp.org
- OWASP LDAP Injection ↗ (opens in a new tab)owasp.org
- OWASP Top 10 A03:2021 Injection ↗ (opens in a new tab)owasp.org
- Oracle Java DirContext search documentation ↗ (opens in a new tab)docs.oracle.com