Here is an example of Java code that is vulnerable to LDAP injection:
🥺 Vulnerable Code
String username = request.getParameter("username");
// Vulnerable: user input is concatenated into the LDAP search filter
String filter = "(&(objectClass=user)(uid=" + username + "))";
DirContext ctx = new InitialDirContext(env);
NamingEnumeration<SearchResult> results =
ctx.search("ou=people,dc=example,dc=com", filter, controls);Parentheses, asterisks, ampersands, and backslashes are all meaningful inside an LDAP filter. A username of *)(uid=*))(|(uid=* rewrites the filter into a wildcard match and dumps the whole directory, while admin)(&(objectClass=* can flip an authentication check into an always-true condition. Nothing here escapes those characters.
😎 Secure Code
Here is a version of the same code that is secured against LDAP injection:
String username = request.getParameter("username");
if (!username.matches("^[a-zA-Z0-9._-]{1,64}$")) {
throw new IllegalArgumentException("Invalid username");
}
// Parameterized filter: the provider escapes {0} per RFC 4515
String filter = "(&(objectClass=user)(uid={0}))";
Object[] filterArgs = new Object[] { username };
DirContext ctx = new InitialDirContext(env);
NamingEnumeration<SearchResult> results =
ctx.search("ou=people,dc=example,dc=com", filter, filterArgs, controls);The allowlist rejects filter metacharacters up front, and the search overload that takes filterArgs escapes the value for you, so {0} can only ever be data. Bind with a least-privileged service account, scope the search base as tightly as possible, and never build a filter with string concatenation.