Java: add experimental java/ldap-dn-injection-library-mode query (CWE-90)#149
Open
tonghuaroot wants to merge 1 commit into
Open
Conversation
Detects LDAP distinguished-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), where the login principal arrives as a method parameter at the library boundary rather than at a remote flow source. The supported java/ldap-injection query starts from ActiveThreatModelSource and reports nothing on such a framework; this variant models the library-boundary sources (login-principal accessors and DN-builder method parameters) that it misses. Anchored on Apache Shiro CVE-2026-49268. Ships a qhelp with bad/good samples and a true-positive / true-negative test.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new experimental Java query,
githubsecuritylab/java/ldap-dn-injection-library-mode, that detects LDAP distinguished-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
The supported
java/ldap-injectionquery starts fromActiveThreatModelSource(remote flow sources). An authentication 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, and the bug survives despite heavy scanning. This query closes that source-boundary gap with library-boundary sources.Sources (library-boundary)
AuthenticationToken.getPrincipal/getUsername, Spring SecurityAuthentication.getName/getPrincipal, andjava.security.Principal.getName.Stringparameter of a method whose name looks like 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 ShiroLdapContextFactory.getLdapContext(theprincipalargument).new LdapName(String)is deliberately excluded (it commonly parses an existing 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 a shared sink library, so it stands alone.The DN escape set (RFC 2253) differs from the LDAP search-filter escape set (RFC 4515): a value escaped for a search filter is still unsafe in a DN, so only DN escapers are treated as sanitizers.
Origin
This was originally proposed as an experimental query in github/codeql#22003. @michaelnebel noted that the Java experimental queries have been migrated to the Community Packs repo and asked that the PR be opened here instead, so this PR ports it.
Adapted to Community Packs conventions:
@idnamespacegithubsecuritylab/java/..., query underjava/src/security/CWE-090/with its qhelp + bad/good samples alongside, test underjava/test/security/CWE-090/(flat, matching the existing Java tests) with.qlref/.expected/options, and the Shiro stubs the test needs added underjava/test/stubs/. The github/codeql-specific change-note and integration-test files were dropped.Contents
java/src/security/CWE-090/LdapDnInjectionLibraryMode.ql— the query (@kind path-problem,@precision medium,experimental).java/src/security/CWE-090/LdapDnInjectionLibraryMode.qhelp— query help.java/src/security/CWE-090/LdapDnInjectionLibraryMode{Bad,Good}.java— qhelp samples.java/test/security/CWE-090/LdapDnInjectionLibraryMode.{java,qlref,expected}+options— true-positive / true-negative test shaped like the Shiro realm (getUserDnconcatenation vsRdn.escapeValue).java/test/stubs/org-apache-shiro-authc-2.0.1/.../UsernamePasswordToken.javaandjava/test/stubs/org-apache-shiro-realm-ldap-2.0.1/.../LdapContextFactory.java— stubs the test needs (theorg-apache-shiro-authc-2.0.1stub directory already exists; this addsUsernamePasswordTokento it and adds therealm-ldapstub).Verification
Verified locally with CodeQL CLI 2.25.6:
codeql query compile --warnings=error java/src/security/CWE-090/LdapDnInjectionLibraryMode.ql— compiles clean, no warnings.codeql query format— idempotent (autoformatted).codeql test run java/test/security/CWE-090— passes: 8 true-positive path results on the three unescaped bind sinks (SECURITY_PRINCIPALenv value, ShirogetLdapContext,Context.lookup), each traced both to the DN-builder parameter and to the auth-token principal accessor; 0 results on theRdn.escapeValue-escaped GOOD methods.