---
title: "Escape input in directory queries · Agent Wranglers"
url: https://agentwranglers.se/playbook/application-security/input-and-injection/ldap-injection
id: APS-98
level: Recommended
updated: 2026-10-27
build: a2a6bdfed830
tokens: 900
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Escape input in directory queries

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Input and injection](https://agentwranglers.se/playbook/application-security/input-and-injection.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-27.

- ID: APS-98
- Level: Recommended
- Chapter: [Input and injection](https://agentwranglers.se/playbook/application-security/input-and-injection.md)
- Rule: Escape every value placed in an LDAP search filter or distinguished name with the library's escape function for that part. Never join raw input into a filter.
- Check: Send `*`, `*)(uid=*))(|(uid=*` and `admin)(&)` as the user name to sign-in and to any directory search. Sign-in fails, and the search returns no more results than for a normal name. A search of the code finds no filter string built from input outside the escape function.
- How: Skip this rule when nothing in the app talks to a directory, such as Active Directory or OpenLDAP. In a search filter, the characters `*`, `(`, `)`, `\` and the null byte change the query. A user name of `*` can match every account, and `*)(uid=*` can turn a sign-in check into one that always passes. Filters and distinguished names escape different characters, so use the function made for each. Bind as a service account with read rights on the users it needs, never as the directory administrator. It is the same idea as [Use parameterised queries](https://agentwranglers.se/playbook/application-security/input-and-injection/sql-injection.md). Prefer a sign-on protocol such as OpenID Connect over checking passwords against the directory yourself.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### Python example

```python
from ldap3.utils.conv import escape_filter_chars

search_filter = f"(&(objectClass=person)(uid={escape_filter_chars(user_name)}))"
conn.search("ou=people,dc=example,dc=com", search_filter, attributes=["cn", "mail"])
```

### Java example

```java
import org.springframework.ldap.support.LdapEncoder;

String filter = "(&(objectClass=person)(uid=" + LdapEncoder.filterEncode(userName) + "))";
List<String> names = ldapTemplate.search("ou=people", filter, (AttributesMapper<String>) attrs -> (String) attrs.get("cn").get());
```

## Sources

- [OWASP LDAP Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html)

## Related rules

- APS-2 [Use parameterised queries](https://agentwranglers.se/playbook/application-security/input-and-injection/sql-injection.md) in Application security

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/application-security/input-and-injection/ldap-injection">Agent Wranglers application security playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Block prototype pollution](https://agentwranglers.se/playbook/application-security/input-and-injection/prototype-pollution.md)
- Next: [Neutralise formulas in spreadsheet exports](https://agentwranglers.se/playbook/application-security/input-and-injection/csv-injection.md)
- [Input and injection](https://agentwranglers.se/playbook/application-security/input-and-injection.md)
