Skip to content

FIX: Detect percent-encoded filters and hex-escaped wildcards in LDAPInjectionOutputScorer (#3324) - #3682

Merged
Roman Lutz (romanlutz) merged 6 commits into
microsoft:mainfrom
Hrushikesh-ramilla:fix/ldap-encoded-filters-and-urls-3324
Nov 2, 2026
Merged

Roman Lutz (romanlutz) merged 6 commits into
microsoft:mainfrom
Hrushikesh-ramilla:fix/ldap-encoded-filters-and-urls-3324

Conversation

@Hrushikesh-ramilla

Copy link
Copy Markdown
Contributor

Description

This PR addresses the LDAP injection detection gaps reported in #3324 for LDAPInjectionOutputScorer (pyrit/score/true_false/regex/ldap_injection_output_scorer.py):

  1. RFC 4515 hex-escaped wildcards (\2a / \2A):
    Under RFC 4515 Section 3, asterisks inside search filter assertion values can be escaped as \2a or \2A. Previously, Filter Break Sequence and Always-True Clause expected literal *, so payloads with hex-escaped wildcards (such as \2a)(uid=*) or )(cn=\2a)) and the all-wildcards-encoded case (such as \2a)(uid=\2a)) bypassed detection completely.

    • Updated Filter Break Sequence and Always-True Clause to support \2a and \2A.
  2. Percent-encoded filter delimiters and characters:
    In web requests and endpoints, LDAP metacharacters are commonly URL/percent-encoded (%28 for (, %29 for ), %2a for *, %3d for =, %7c for |, %26 for &, %21 for !).

    • Extended Filter Break Sequence, Always-True Clause, Boolean Operator Injection, and Null Byte Filter Termination to recognize both plain and percent-encoded characters (e.g., %2a%29%28uid=%2a%29, %29%28cn=%2a%29, %29%7c%28objectClass=%2a%29, admin*%29%00).
  3. LDAP URLs with search filter queries (RFC 4516):
    Added a new LDAP URL Filter Injection pattern that detects ldap:// and ldaps:// URLs carrying search filter queries (e.g., ldap://127.0.0.1/dc=example,dc=com???%28uid=%2a%29 or ldap://localhost:389/???%2a%29%28uid=%2a%29).

Addresses the LDAP injection portion of #3324 (following the split PR guidance in #3324 and sister PRs #3262, #3326, #3597, #3679).

Tests and Documentation

  • Updated tests/unit/score/regex/test_ldap_injection_output_scorer.py:
    • Added 27 new positive test cases covering hex-escaped wildcards (\2a, \2A), URL-encoded wildcards (%2a, %2A), all-wildcards-encoded filter breaks, percent-encoded clauses, and LDAP/LDAPS URLs.
    • Added negative test cases for benign LDAP URLs and non-injection query parameters to prevent false positives.
    • Added rationale assertions verifying Always-True Clause and LDAP URL Filter Injection.
  • Updated class docstring in ldap_injection_output_scorer.py.
  • Validation:
    • uv run pytest tests/unit/score/regex/test_ldap_injection_output_scorer.py: 84 passed.
    • uv run pytest tests/unit/score/regex/: 1,242 passed (100% green).
    • uv run ruff check pyrit/score/true_false/regex/ldap_injection_output_scorer.py tests/unit/score/regex/test_ldap_injection_output_scorer.py: Clean.
    • uv run ruff format --check pyrit/score/true_false/regex/ldap_injection_output_scorer.py tests/unit/score/regex/test_ldap_injection_output_scorer.py: Clean.
    • uv run ty check pyrit/score/true_false/regex/ldap_injection_output_scorer.py tests/unit/score/regex/test_ldap_injection_output_scorer.py: Clean.

@romanlutz Roman Lutz (romanlutz) self-assigned this Nov 1, 2026
Preserve custom pattern matching and decode only LDAP filter fields once. Add persisted-score and boundary regressions for encoded attribute names, benign filters, literal escapes, and double encoding.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Integrate microsoft/PyRIT main at f02928e.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@romanlutz
Roman Lutz (romanlutz) added this pull request to the merge queue Nov 2, 2026
Merged via the queue into microsoft:main with commit cef151a Nov 2, 2026
95 of 101 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants