Java: add experimental java/ldap-dn-injection-library-mode query#22003
Java: add experimental java/ldap-dn-injection-library-mode query#22003tonghuaroot wants to merge 1 commit into
Conversation
The supported java/ldap-injection query starts from remote flow sources, so it does not report on authentication frameworks, where the login principal arrives as a method parameter rather than at a servlet parameter or similar. This experimental query detects LDAP distinguished-name injection (CWE-90, RFC 2253) into a bind DN inside such a framework. Sources are library-boundary values: login-principal accessors of common auth frameworks (Apache Shiro AuthenticationToken, Spring Security Authentication, java.security.Principal) and the string parameters of DN-builder-shaped methods. The DN-builder source model is name-heuristic, a deliberate precision/recall trade for the library case where there is no remote flow source to anchor on; the query is therefore experimental and medium precision. Sinks are the bind-DN positions: javax.naming Context / DirContext bind, rebind, lookup, lookupLink, createSubcontext; the java.naming.security.principal environment value; and Apache Shiro LdapContextFactory.getLdapContext. Barriers are RFC 2253 DN escapers such as Rdn.escapeValue. Anchored on Apache Shiro CVE-2026-49268. Adds a qhelp, a true-positive/true-negative test, and the Shiro stubs the test needs.
|
@tonghuaroot : Like the C# experimental queries, the Java experimental queries have been migrated to the Community packs repo. I have pinged the owners of the Community packs repo on the incoming C# PR. Thank you very much for contributing! |
|
Thanks @michaelnebel. I've reopened this against the Community Packs repo as you suggested: GitHubSecurityLab/CodeQL-Community-Packs#149 The query, qhelp, bad/good samples, test, and the Shiro stubs are all ported there, adapted to the Community Packs conventions ( |
What
A new experimental query,
java/ldap-dn-injection-library-mode, that detects LDAPdistinguished-name injection (CWE-90, RFC 2253) into a bind DN inside an
authentication library or framework (Apache Shiro, a custom Spring Security realm,
a CAS / pac4j SPI, a Keycloak provider).
Why the supported query misses this
java/ldap-injectionstarts fromActiveThreatModelSource(remote flow sources). Anauth framework has none — the login principal arrives as a method parameter, not
as a servlet parameter or request body. On a framework database the supported query
therefore has zero sources, regardless of the sink model. This query closes that
source-boundary gap with library-boundary sources.
Sources (library-boundary)
AuthenticationToken.getPrincipal/getUsername, Spring SecurityAuthentication.getName/getPrincipal,java.security.Principal.getName.Stringparameter of a method whose name lookslike a DN builder (
getUserDn,*UserDn,buildDn,resolveDn,getUsernameWithSuffix,get*Principal, ...).Honest caveat — the DN-builder source model is name-heuristic. It keys partly off
method names. This is a deliberate precision/recall trade for the library case where
there is no remote flow source to anchor on: a framework that builds the DN in a
differently named helper is missed, and a benign method that matches the name pattern
may produce a false positive. This is why the query is
experimentaland@precision medium, and the trade-off is documented in both the QLDoc and the qhelp.Triage a result by confirming the value reaches a real bind sink unescaped.
Sinks (bind DN)
javax.namingContext/DirContextbind/rebind/lookup/lookupLink/createSubcontext(theString nameargument); thejava.naming.security.principalenvironment value; and Shiro
LdapContextFactory.getLdapContext(theprincipalargument).
new LdapName(String)is deliberately excluded (it commonly parses anexisting cert/principal DN, not a fresh one for a bind). Barriers are RFC 2253 DN
escapers (
Rdn.escapeValue, SpringLdapEncoder.nameEncode, ESAPIencodeForDN).The query defines its sinks inline rather than reusing the supported
LdapInjectionSinklibrary, so it stands alone and does not depend on the companionbind-DN-sinks PR being merged first.
Evidence (Apache Shiro CVE-2026-49268)
CVE-2026-49268 (fixed 2.2.1 / 3.0.0-alpha-2). Built a database from
apache/shiro@shiro-root-2.2.0and ran a 3-way comparison:java/ldap-injectionjava/ldap-injection+ bind-DN sinks (companion PR)java/ldap-dn-injection-library-mode(this PR)The 8 results land on exactly the patched code:
DefaultLdapRealm.getUserDn/getLdapContext(principal, ...)andActiveDirectoryRealm.getUsernameWithSuffix, withthe source correctly traced to
AuthenticationToken.getUsername()/getPrincipal().This satisfies the experimental-query requirement of at least one true positive on a
real project.
Tests / help
Ships a qhelp (with bad/good samples) and a true-positive / true-negative test shaped
like the Shiro realm (
getUserDnconcatenation vsRdn.escapeValue), plus the Shirostubs the test needs.
codeql test runis green and the query compiles with--warnings=error.