| name | run2_druid-cve-2021-25646 |
| description | Complete guide to patching Apache Druid CVE-2021-25646 - JavaScript RCE via Jackson @JacksonInject bypass with empty JSON key |
Apache Druid CVE-2021-25646 - Complete Patch Guide
Vulnerability Summary
CVE-2021-25646 - Remote Code Execution in Apache Druid <= 0.20.0
Attack Vector: Authenticated attackers send crafted JSON to /druid/indexer/v1/sampler
Root Cause: @JacksonInject(useInput = DEFAULT) allows JSON to override server-injected JavaScriptConfig
CVSS: Critical
How the Exploit Works
- Druid uses
@JacksonInject JavaScriptConfig config to inject server-side config (JS disabled by default)
- Jackson's
@JacksonInject with useInput = OptBoolean.DEFAULT allows JSON to OVERRIDE the injectable
- The empty JSON key
"" acts as the Jackson injection ID for the JavaScriptConfig parameter
- Attacker sends
"": {"enabled": true} → Jackson creates a new JavaScriptConfig(enabled=true)
- This overrides the server's config → JavaScript executes arbitrary code via
Runtime.exec()
{
"type": "javascript",
"function": "function(){ java.lang.Runtime.getRuntime().exec('malicious_cmd'); }",
"": { "enabled": true }
}
The Fix
Change useInput from default (DEFAULT/TRUE behavior) to OptBoolean.FALSE on ALL
@JacksonInject JavaScriptConfig config parameters:
@JacksonInject JavaScriptConfig config
@JacksonInject(useInput = OptBoolean.FALSE) JavaScriptConfig config
Also add: import com.fasterxml.jackson.annotation.OptBoolean;
All 7 Affected Files
| File | Module |
|---|
core/src/main/java/org/apache/druid/data/input/impl/JavaScriptParseSpec.java | core |
processing/src/main/java/org/apache/druid/query/filter/JavaScriptDimFilter.java | processing |
processing/src/main/java/org/apache/druid/query/aggregation/JavaScriptAggregatorFactory.java | processing |
processing/src/main/java/org/apache/druid/query/aggregation/post/JavaScriptPostAggregator.java | processing |
processing/src/main/java/org/apache/druid/query/extraction/JavaScriptExtractionFn.java | processing |
server/src/main/java/org/apache/druid/server/router/JavaScriptTieredBrokerSelectorStrategy.java | server |
indexing-service/src/main/java/org/apache/druid/indexing/overlord/setup/JavaScriptWorkerSelectStrategy.java | indexing-service |
Build Command
The sampler is in indexing-service; build with -pl indexing-service -am to build it and dependencies:
cd /root/druid
mvn clean package -DskipTests \
-Dcheckstyle.skip=true -Dpmd.skip=true -Dforbiddenapis.skip=true \
-Dspotbugs.skip=true -Danimal.sniffer.skip=true -Denforcer.skip=true \
-Djacoco.skip=true -Ddependency-check.skip=true \
-pl '!web-console' -pl indexing-service -am
Output JAR: indexing-service/target/druid-indexing-service-0.20.0.jar
Patch File Generation
After applying source changes:
git diff > /root/patches/cve-2021-25646-javascript-inject-bypass.patch
Verification
After patch, the exploit payload returns HTTP 500 with "JavaScript is disabled"
(from Preconditions.checkState(config.isEnabled(), "JavaScript is disabled"))
because the injected value (enabled=false) can no longer be overridden by JSON.