Feb 10, 2026·6 min read·23 visits
If you use LDAP for Apache Druid authentication and your LDAP server allows anonymous binds (a common default), anyone can log in as 'admin' by sending an empty password. CVSS 9.8. Upgrade to 36.0.0 immediately or disable anonymous binds in LDAP.
Apache Druid, the high-performance real-time analytics database, has dropped the ball on basic authentication logic. By failing to differentiate between an 'anonymous' LDAP bind and a 'user' LDAP bind, Druid allows attackers to log in as any user—including administrators—simply by providing an empty password. This is a classic protocol confusion vulnerability that turns a misconfigured LDAP server into a golden key for your data warehouse.
In the world of high-speed analytics, Apache Druid is the muscle car. It ingests massive streams of event data and lets you query it with sub-second latency. But like a muscle car with no door locks, speed doesn't matter if someone can just hop in and drive it off a cliff.
CVE-2026-23906 is what happens when a developer trusts a protocol response a little too much. It resides in the druid-basic-security extension, specifically the LDAP authenticator. This component is responsible for taking a username and password from the web console, passing it to your corporate LDAP/Active Directory, and asking, "Is this guy legit?"
The problem isn't that Druid fails to ask the question. The problem is that it misunderstands the answer. It’s the digital equivalent of a bouncer asking a club owner, "Is the club open to the public?" and when the owner says "Yes," the bouncer assumes the random guy in the hoodie is the VIP on the guest list.
To understand this vulnerability, you have to understand a quirk of the LDAP protocol that has plagued sysadmins since the 90s: the Anonymous Bind.
In LDAP (Lightweight Directory Access Protocol), a client initiates a session by sending a 'Bind Request'. This request usually contains a Distinguished Name (DN) and a password. However, the protocol spec allows for an 'unauthenticated' state. If a client sends a Bind Request with a DN but an empty password (length zero), the server interprets this not as a login attempt for that specific user, but as a request for an anonymous session.
If the LDAP server is configured to allow anonymous access (which, terrifyingly, is the default in many older OpenLDAP configs and some Active Directory setups for compatibility), it returns LDAP_SUCCESS (Code 0).
Here is where Druid trips over its own shoelaces. The authentication logic flows like this:
admin and "" (empty string).Success.Success and thinks, "Great! The password for admin was correct!"admin.Druid essentially confuses "The server allowed a connection" with "The user proved their identity."
While the exact patch involves specific Druid internal classes, the vulnerability pattern is textbook Java JNDI misuse. Let's look at a reconstruction of the vulnerable logic versus the secure implementation.
The code creates an InitialDirContext using the credentials provided by the user. If the constructor doesn't throw an exception, the code assumes authentication succeeded.
// VULNERABLE PSEUDO-CODE
public boolean authenticate(String userDn, String password) {
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, ldapUrl);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, userDn);
// FATAL FLAW: No check for empty password here
env.put(Context.SECURITY_CREDENTIALS, password);
try {
// If this succeeds, Druid assumes the userDN matches the password.
// But if password is "", LDAP returns success for Anonymous!
DirContext ctx = new InitialDirContext(env);
ctx.close();
return true;
} catch (NamingException e) {
return false;
}
}The fix is embarrassingly simple: Do not attempt to bind if the password is empty. Alternatively, explicitly disable anonymous pools in the connection config, but the explicit check is safer at the application level.
// PATCHED LOGIC
public boolean authenticate(String userDn, String password) {
// THE FIX: Explicitly reject empty passwords
if (password == null || password.trim().isEmpty()) {
LOG.warn("Auth failed: Empty password provided for user " + userDn);
return false;
}
Properties env = new Properties();
// ... rest of the setup ...
try {
DirContext ctx = new InitialDirContext(env);
return true;
} catch (NamingException e) {
return false;
}
}It is a simple if statement that stands between your data and the internet.
Exploiting this is trivial. You don't need a buffer overflow, you don't need a heap spray, and you don't need complex gadgets. You just need curl and a lack of morals.
First, identify an Apache Druid instance. They typically listen on ports 8081 (Coordinator) or 8888 (Router). If the druid-basic-security extension is on, you'll be greeted with a login prompt.
You need a valid username. admin is the default hardcoded user in many setups. druid is another common one. If you can enumerate users (via a different leak or guessing common names like jdoe), you can impersonate them.
Capture the login request (usually a POST to /druid-ext/basic-security/authentication/db/basic/login or similar, depending on the exact auth provider mapping). Replay it with an empty password.
# The "Hacker" Command
curl -i -X POST https://target-druid:8888/druid/v2/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": ""}'If the backend LDAP allows anonymous binds:
HTTP/1.1 200 OK
Set-Cookie: druid.session=eyJhbGciOiJIUzI1NiJ9...; Path=/; HttpOnly
Content-Type: application/json
{"user": "admin", "roles": ["admin"]}Boom. You now have a session cookie for the admin user. You can now access the Druid console, drop tables, or submit malicious ingestion tasks that could lead to Remote Code Execution (RCE) on the cluster nodes.
Druid isn't just a database; it's a distributed system often running with significant privileges to access cloud storage (S3, GCS) and HDFS.
1. Full Data Compromise: An attacker can query all data. In many organizations, Druid holds aggregated, sensitive business intelligence data.
2. Data Destruction: With admin access, an attacker can mark segments as 'unused', effectively deleting petabytes of historical data instantly.
3. Potential RCE: This is the scary part. Druid allows 'Ingestion Specs'. These are JSON instructions on how to load data. While Druid has sandboxing, a privileged user can often configure ingestion tasks to read files from the local filesystem of the detailed nodes, or use JDBC lookups to attack internal databases. In some configurations, Java-based ingestion tasks or JavaScript functions (if enabled) can lead to full Remote Code Execution.
You have two options: fix the application or fix the infrastructure. Do both.
Apache Druid version 36.0.0 introduces the check for empty passwords. Upgrade immediately. This ensures that even if your LDAP server is promiscuous, Druid won't take the bait.
Why does your LDAP server allow anonymous binds in 2026? Stop that.
disallow bind_anon in your slapd.conf.DsHeuristics attribute is set to disable anonymous access (though AD usually disables this by default on newer forests, legacy setups drift).This is a classic 'Defense in Depth' scenario. The application shouldn't be vulnerable, but the infrastructure shouldn't be permissive.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Apache Druid Apache | >= 0.17.0, < 36.0.0 | 36.0.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-287 (Improper Authentication) |
| Attack Vector | Network |
| CVSS | 9.8 (Critical) |
| Impact | Full Admin Access / Potential RCE |
| EPSS Score | 0.03% |
| Exploit Status | Trivial / Conceptual |