Security Resources

⌘K
  1. Home
  2. Security Resources
  3. Secure Code Explain
  4. LDAP Injection

LDAP Injection

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.