RSTR-LDAP-002 — Python LDAP filter built with f-string
Summary
A Python LDAP search builds the filter string from request input via
an f-string or .format(...). An attacker submitting *)(uid=* (or
similar metacharacter payloads) bypasses authentication or enumerates
the directory.
This is the Python counterpart of RSTR-LDAP-001.
Severity
High.
Languages
Python (ldap3, python-ldap).
What rastray flags
conn.search(base_dn, f'(uid={user})', search_scope=SUBTREE) # ← flagged
conn.search_s(base_dn, ldap.SCOPE_SUBTREE,
'(uid={})'.format(user)) # ← flagged
What rastray deliberately does not flag
- Filters built from literal strings.
- Filters built with
ldap3.utils.conv.escape_filter_chars(...)first. - Filters built from a parsed/validated identifier (e.g. a UUID).
How to fix it
Escape the input with the library's escape helper:
from ldap3.utils.conv import escape_filter_chars
conn.search(base_dn,
f'(uid={escape_filter_chars(user)})',
search_scope=SUBTREE)
For python-ldap:
import ldap.filter
filter_str = ldap.filter.filter_format('(uid=%s)', [user])
conn.search_s(base_dn, ldap.SCOPE_SUBTREE, filter_str)
filter_format parametrises like a prepared statement — it's the
LDAP equivalent of ? placeholders.