ASVS 5.0 V1.2.6 (Level 2) requires that your application is protected against LDAP injection, or that specific controls to prevent it are in place. In practice that means escaping untrusted values with the LDAP filter or DN escaping rules before they enter a search filter or distinguished name.
Why it matters
Directory logins often run a filter such as (&(uid=USER)(userPassword=PASS)). If USER is *)(uid=*))(|(uid=*, the filter changes shape and may match every account (CWE-90). Attackers use the same trick to enumerate attributes and bypass authentication.
How to implement it
Never concatenate. Use the escaping function your LDAP library provides, with separate rules for filters and for DNs, since they escape different characters.
from ldap3.utils.conv import escape_filter_chars
from ldap3.utils.dn import escape_rdn
safe_uid = escape_filter_chars(username)
search_filter = f"(&(objectClass=person)(uid={safe_uid}))"
user_dn = f"uid={escape_rdn(username)},ou=people,dc=example,dc=com"
Better, do a bind with the user's own credentials after finding the entry, rather than comparing password attributes in a filter. Also validate the username against an allowlist pattern before you escape, and limit search size and scope.
How to test it
Log in with usernames *, admin)(&, *)(uid=* and \00. Each must fail like a wrong user, with no errors that show filter text and no extra matches. Review logs to confirm the filter contains escaped sequences such as \2a.
Common mistakes
- Escaping for filters but using the same function for DNs.
- Building the filter first and escaping the whole string.
- Using an anonymous bind that returns more than needed.
Where this goes wrong in practice
The usual setup is a corporate login against Active Directory or OpenLDAP. The developer builds the filter with an f string because the examples online do, and the form works in testing with ordinary names. The flaw only shows with hostile input, which is why code reviews that only try valid users miss it.
Two related details help. First, bind as a low privilege service account for the search and then bind as the user with the supplied password, so the application never compares password attributes itself. Second, set size and time limits on searches, so a wildcard cannot pull the whole directory.
Quick check
Do filters and DNs use the same escaping?
No. They have different special characters, so use the matching function for each.