Skip to content
KitploitKITPLOIT
ToolsBlog
Log in
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2025-59059-Misattributed-RCE-in-Apache-Ranger-Static-Analysis-Correction — CVE-2025-59059: Misattributed RCE in Apache Ranger Static Analysis Correction | Kitploit
Tools/GitHubGitHub/pl4tyz/cve-2025-59059-misattributed-rce-in-apache-ranger-static-analysis-correction
Static AnalysisVulnerability AnalysisCode AnalysisExploitationWeb SecurityLearning & Education
GitHubpl4tyz/cve-2025-59059-misattributed-rce-in-apache-ranger-static-analysis-correction

CVE-2025-59059-Misattributed-RCE-in-Apache-Ranger-Static-Analysis-Correction

CVE-2025-59059: Misattributed RCE in Apache Ranger Static Analysis Correction

View Repository
296 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2025-59059: Misattributed RCE in Apache Ranger a correction

CVE: CVE-2025-59059
Affected versions: Apache Ranger <= 2.7.0
Fixed in: Apache Ranger 2.8.0
CVSS (official): 9.8 Critical
Actual severity (argued): ~6.0 Medium — see analysis below


Preface

this write-up isnt about a new exploit or a working PoC. the point here is to correct whats wrong with the public disclosure on CVE-2025-59059 specifically two things: the wrong class got named as the vulnerable component, and the CVSS score doesnt reflect the actual exploitability constraints. everything here is based on static code analysis of the Apache Ranger 2.7.0 source and the patch diff that went into 2.8.0.


What the advisory says

the official advisory reads:

"Remote Code Execution Vulnerability in NashornScriptEngineCreator is reported in Apache Ranger versions <= 2.7.0."

this is wrong, or at least misleading. NashornScriptEngineCreator is not the vulnerable class. if anything its the better hardened of the two Nashorn-related components in the codebase — which we'll get into.


Background: Nashorn in Apache Ranger

Apache Ranger uses JavaScript expressions to evaluate row-level filter policies. these are rules that decide whether a given user gets access to a specific record in a dataset. to actually run those expressions on the JVM, Ranger embeds a JavaScript engine. in versions <= 2.7.0 that engine is Nashorn, Oracles built-in JS engine that shipped with JDK 8 through 14.

one thing the advisory completly omits — and this matters a lot for scoping impact — is that jdk.nashorn.api.scripting.NashornScriptEngineFactory is not part of Rangers source code at all. its a JDK built-in. it was included in JDK 8, deprecated in JDK 11, and fully removed in JDK 15. so this vuln is only reachable if youre running Ranger on JDK 8 through 14. anything on JDK 15+ isnt affected because Nashorn simply doesnt exist there, and ScriptEngineUtil just falls through to GraalJS or JavaScriptEngineCreator silently.

two classes in Ranger use Nashorn. they treat it very differently.


The two Nashorn-related classes

1. NashornScriptEngineCreator — the named but safer one

located at:

agents-common/src/main/java/org/apache/ranger/plugin/util/NashornScriptEngineCreator.java
public class NashornScriptEngineCreator implements ScriptEngineCreator {

    private static final String[] SCRIPT_ENGINE_ARGS = new String[] {
        "--no-java", "--no-syntax-extensions"
    };

    @Override
    public ScriptEngine getScriptEngine(ClassLoader clsLoader) {
        NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
        ret = factory.getScriptEngine(SCRIPT_ENGINE_ARGS, clsLoader, RangerClassFilter.INSTANCE);
        ...
    }

    private static class RangerClassFilter implements ClassFilter {
        @Override
        public boolean exposeToScripts(String className) {
            LOG.warn("script blocked: attempt to use Java class {}", className);
            return false;
        }
    }
}

this class actually does three things to harden the engine:

  • --no-java — cuts off direct access to the java.* namespace from inside scripts
  • --no-syntax-extensions — disables non-standard Nashorn syntax
  • RangerClassFilter — blocks all Java class access at the ClassFilter level, returns false for everything

is it bulletproof? no. Nashorn ClassFilter bypasses exist through reflection chains and java.lang.invoke tricks. but its meaningfully more locked down than what we find in the other class.


2. RecordFilterJavaScript the actual vulnerable class

located at:

plugin-nestedstructure/src/main/java/org/apache/ranger/authorization/nestedstructure/authorizer/RecordFilterJavaScript.java
public class RecordFilterJavaScript {

    static class SecurityFilter implements ClassFilter {
        @Override
        public boolean exposeToScripts(String s) {
            return false;
        }

        boolean containsMalware(String filterExpr) {
            // only checks for this one specific string
            return filterExpr.contains("this.engine");
        }
    }

    public static boolean filterRow(String user, String filterExpr, String jsonString) {
        SecurityFilter securityFilter = new SecurityFilter();

        if (securityFilter.containsMalware(filterExpr)) {
            throw new MaskingException("cannot process filter expression due to security concern...");
        }

        // instantiates Nashorn directly — no --no-java, no --no-syntax-extensions
        NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
        ScriptEngine engine = factory.getScriptEngine(securityFilter);

        String script = " jsonAttr = JSON.parse(jsonString); " + filterExpr;

        Bindings bindings = engine.createBindings();
        bindings.put("jsonString", jsonString);
        bindings.put("user", user);

        boolean hasAccess = (boolean) engine.eval(script, bindings);
        ...
    }
}

compare this to NashornScriptEngineCreator and the difference is pretty obvious:

  • no --no-java flag java.* namespace is fully open to scripts
  • no --no-syntax-extensions
  • the only "security" is one string check: filterExpr.contains("this.engine")
  • filterExpr gets concatenated directly into the script that Nashorn evaluates

because --no-java isnt passed, the java.* namespace is fully accessible. you dont need any bypass technique at all:

var runtime = java.lang.Runtime.getRuntime();
runtime.exec("id");

no this.engine anywhere in there. the blacklist is completely irrelevent to this attack path.

whats interesting is that the developers clearly knew about at least one bypass pattern. the test file TestRecordFilterJavaScript.java has this:

RecordFilterJavaScript.filterRow("user",
    "this.engine.factory.scriptEngine.eval('java.lang.Runtime.getRuntime().exec(\"/Applications/Spotify.app/Contents/MacOS/Spotify\")')",
    ...);

that test exists to confirm this.engine gets blocked. what wasnt blocked is the direct java.* path, which doesnt need this.engine at all.


The entry point

RecordFilterJavaScript.filterRow() is only called from one place:

plugin-nestedstructure/src/main/java/org/apache/ranger/authorization/nestedstructure/authorizer/NestedStructureAuthorizer.java
private boolean hasAccessToRecord(String schema, String user, ..., String jsonString, ...) {
    RangerAccessResult result = plugin.evalRowFilterPolicies(request, null);

    if (result.isRowFilterEnabled()) {
        String filterExpr = result.getFilterExpr();
        ret = RecordFilterJavaScript.filterRow(user, filterExpr, jsonString);
    }
    return ret;
}

filterExpr comes from result.getFilterExpr() thats the JavaScript expression stored in a Ranger row filter policy. an attacker with policy admin privileges can set that expression to whatever they want. when any user then hits a resource governed by that policy, hasAccessToRecord() fires, pulls filterExpr from the policy store, and filterRow() hands it to Nashorn with basically no sandboxing.

attack chain:

Policy admin access
       |
       v
Create/modify a row filter policy on a nestedstructure resource
       |
       v
filterExpr set to: java.lang.Runtime.getRuntime().exec("...")
       |
       v
Any user accesses the resource → hasAccessToRecord() triggered
       |
       v
filterExpr flows into filterRow() → Nashorn evaluates it → RCE

The patch diff

the fix is tracked as RANGER-4076: Remove Nashorn Script Engine, commited December 8, 2025 by Kishor Gollapalliwar. pulled from the Apache mailing list commit archive. three files changed, 27 insertions, 81 deletions.

commit 923a8473de2985cd389d45062cd4717d5ca13235
Author: Kishor Gollapalliwar
AuthorDate: Mon Dec 8 14:55:56 2025 +0530
Download Tool