Skip to main content
VulnerabilityPublished

CVE-2026-11748: LY Central Dogma · LDAP Injection

Affects LY Central DogmaSource CVE Database V5

0
Compare

Not known to be exploited · CVSS 6.9 Medium · patch available : update LY Central Dogma when convenient.

Data as of 5 Nov 2026, 23:24 UTC

CVSS 4.0 base score
6.9Medium
How severe the flaw is on the 0–10 CVSS scale.
EPSS
0.4% chance of exploitation in 30 days – higher than 41% of CVEsExploit Prediction Scoring System: the likelihood attackers will use this flaw soon.
Patch
Available
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:L/SI:N/SA:N

Exploitation evidence

  1. Disclosed: evidence found.

    CVE published 22 Jun 2026

  2. Detectable: no evidence on record.

    No public nuclei template indexed

  3. Weaponized: no evidence on record.

    No public exploit code indexed in Metasploit or Exploit-DB

  4. Exploited in the wild: no evidence on record.

    Not in CISA KEV and no source reports exploitation

  5. Observed by OffSeq Mirage: no evidence on record.

    No attack traffic recorded by OffSeq Mirage sensors

A missing step is not evidence of safety. Sources: cve.org (opens in a new tab), the Metasploit, Exploit-DB and nuclei-templates index as of 5 Nov 2026.

What to do

Affected software

ProductAffectedFixed in
LY CorporationCentral DogmaAffected–Fixed in–

AI-suggested

If you cannot patch yet, consider restricting access to the authentication service and applying LDAP input validation or filtering as a temporary mitigation if feasible.

Description

# Vulnerability `SearchFirstActiveDirectoryRealm.findUserDn()` substitutes the user-supplied username from the login form into an LDAP search filter template (default `cn={0}`) **without escaping RFC 4515 filter metacharacters** (`*`, `(`, `)`, `\`, NUL). Combined with `SearchControls.setCountLimit(1)` on the same call site, this allows three distinct attack primitives: 1. **Authentication confusion** — typing username `*` causes the realm to construct filter `cn=*`, return the first directory entry (typically a privileged account in AD ordering), and attempt bind against that DN with the attacker's password. 2. **Audit log evasion** — payload `bob)(uid=alice` is recorded verbatim in audit logs while the realm searches with the malformed filter, breaking accountability/compliance (SOX, PCI-DSS, ISO 27001). 3. **Directory enumeration** — wildcards and timing differences allow reconnaissance of OU structure and admin group membership. A repo-wide search for any LDAP escape helper (`escapeLdap`, `encodeFilter`, `escapeFilter`, `ldapEscape`) returns **zero hits** — the defense is not just missing, it was never added. > **Applicability note:** This realm is opt-in. The shipped default LDAP example (`dist/src/conf/shiro.example.ldap.ini`) uses Shiro's `DefaultLdapRealm` with `userDnTemplate` and is **NOT** affected. However, the realm exists precisely to support Active Directory environments where users log in via `sAMAccountName` and the realm must search for the DN first — the canonical LINE corporate AD-backed SSO scenario. Internal deployments using AD-backed login almost certainly select this realm. --- ## Evidence **File:** `server-auth/shiro/src/main/java/com/linecorp/centraldogma/server/auth/shiro/realm/SearchFirstActiveDirectoryRealm.java` **Lines 148–176** on branch `main` @ commit `d64a5151`: ```java @Nullable protected String findUserDn(LdapContextFactory ldapContextFactory, String username) throws NamingException { LdapContext ctx = null; try { ctx = ldapContextFactory.getSystemLdapContext(); final SearchControls ctrl = new SearchControls(); ctrl.setCountLimit(1); // line 156 — returns FIRST match only ctrl.setSearchScope(SearchControls.SUBTREE_SCOPE); ctrl.setTimeLimit(searchTimeoutMillis); final String filter = searchFilter != null ? USERNAME_PLACEHOLDER.matcher(searchFilter) .replaceAll(username) // line 162 — RAW SUBSTITUTION : username; // line 163 final NamingEnumeration result = ctx.search(searchBase, filter, ctrl); ... ``` `USERNAME_PLACEHOLDER = Pattern.compile("\\{0}")`. Default `searchFilter = "cn={0}"`. ### Data flow from HTTP login to vulnerable substitution | Step | Component | |------|-----------| | HTTP login form | `POST /api/v1/login` form field `username` | | `ShiroLoginService.usernamePassword()` (lines 198–223) | applies `loginNameNormalizer` (Unicode lowercase only — **NOT** LDAP escape) | | `Subject.login(new UsernamePasswordToken(username, password))` | Shiro hand-off | | `ActiveDirectoryRealm.doGetAuthenticationInfo` (Shiro core) | calls `queryForAuthenticationInfo0` | | `SearchFirstActiveDirectoryRealm.findUserDn(factory, upToken.getUsername())` | username flows in **verbatim** | ### Repository-wide escape helper grep | Search term | Hits | |-------------|------| | `escapeLdap` | 0 | | `encodeFilter` | 0 | | `escapeFilter` | 0 | | `ldapEscape` | 0 | --- ## PoC Self-contained JUnit 5 test using UnboundID `InMemoryDirectoryServer` (in-process, no external LDAP required). Drop into `server-auth/shiro/src/test/java/com/linecorp/centraldogma/server/auth/shiro/realm/LdapInjectionPoCTest.java` and add `com.unboundid:unboundid-ldapsdk:7.0.0` as a test dependency. > The PoC works by subclassing the realm and overriding `findUserDn()` to capture the actual LDAP filter string sent to the directory — the captured filter is the structural evidence, independent of LDAP server strictness about bind outcomes. ```java /* * Copyright 2026 LINE Corporation * * SECURITY PoC — NOT FOR MERGE INTO THE MAIN TEST SUITE. * * This JUnit class demonstrates the LDAP filter injection in * SearchFirstActiveDirectoryRealm. Drop into * server-auth/shiro/src/test/java/com/linecorp/centraldogma/server/auth/shiro/realm/ * Adds the UnboundID LDAP SDK as a test dep. */ package com.linecorp.centraldogma.server.auth.shiro.realm; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import javax.naming.directory.SearchControls; import javax.naming.ldap.LdapContext; import org.apache.shiro.realm.ldap.JndiLdapContextFactory; import org.apache.shiro.realm.ldap.LdapContextFactory; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll;

References

Community reviews

Loading reviews…