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.

This repository is a benign security proof-of-concept for the huntr Model File Vulnerability program (Protect AI). It contains no real model and no code execution — only oversized nested Java data used to demonstrate a denial-of-service on model load.

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

DL4J ModelSerializer — Denial-of-Service via unbounded, unfiltered Java deserialization of preprocessor.bin

Security proof-of-concept for the huntr Model File Vulnerability (MFV) program. This is not a real model — edgecase.zip is a crafted DL4J model archive that demonstrates an availability (DoS) vulnerability. It contains no code, no external command, no gadget — only a large, valid nested Java data object.

Summary

Eclipse DeepLearning4j's ModelSerializer.restoreMultiLayerNetwork(File) (and restoreComputationGraph) eagerly deserializes the archive entry preprocessor.bin with an unfiltered java.io.ObjectInputStream.readObject() — no ObjectInputFilter/allowlist, and no integrity/size/signature check on the untrusted file before the object graph is built. Loading a crafted .zip whose preprocessor.bin holds a large nested object graph causes uncontrolled heap growth and a deterministic OutOfMemoryError — a DoS on any service that loads an untrusted DL4J model.

  • Affected: DL4J .zip model via org.deeplearning4j.util.ModelSerializer, tested on deeplearning4j-nn:1.0.0-M2.1 (sink also on master, unpatched).
  • Class: CWE-502 (Deserialization of Untrusted Data) → resource exhaustion / DoS. (The same unfiltered readObject sink is the classic Java insecure-deserialization RCE primitive when a gadget lib is on the loader's classpath — not demonstrated here.)

PoC file (edgecase.zip, in this repo)

A valid tiny DL4J model saved with ModelSerializer.writeModel(net, "baseline.zip", true), then copied and given ONE extra entry preprocessor.bin = ObjectOutputStream.writeObject(payload) where payload is a plain nested structure: a List of 2,000 HashMaps × 400 entries + a 300-deep Map→Map chain (~800,300 nodes; ~37 MB serialized, ~5.3 MB on disk after deflate).

edgecase.zip
├── configuration.json   (3,076 B)   # valid model config
├── coefficients.bin     (381 B)
├── updaterState.bin      (649 B)
└── preprocessor.bin  (39,175,202 B)  # large nested Java object graph

Measured impact (JDK 21, DL4J 1.0.0-M2.1, Linux)

load -Xmx wall peak heap outcome
baseline.zip 512 MB 372 ms 17 MB OK
edgecase.zip 512 MB 816 ms 304 MB ClassCastException after full deserialize
edgecase.zip 256 MB 992 ms 246 MB OutOfMemoryError: Java heap space during preprocessor.bin deserialization

Heap blows up ~25× (12→304 MB) and ~57× vs the on-disk file size (deflate hides the cost). A larger crafted structure exhausts any fixed heap (unbounded). The type check (ClassCastException) fires only after readObject() builds the whole graph — the cost is already paid.

Trigger conditions

Any call to ModelSerializer.restoreMultiLayerNetwork(...) / restoreComputationGraph(...) on an untrusted .zip containing a preprocessor.bin entry. No auth, no host access, no special prerequisites — the entry is deserialized automatically before any type/validity check.

No integrity check (bytecode-verified, javap -c)

  • checkInputStream(is) = only is.available() > 0.
  • loadZipData(is) reads each entry into a Map<String,byte[]>; the only guard is ZipEntry.getSize() > Integer.MAX_VALUE (2 GB) — no smaller per-entry cap, no total-size cap, no CRC/digest/signature.
  • preprocessor.binnew ObjectInputStream(new ByteArrayInputStream(bytes)).readObject() then checkcast DataSetPreProcessor (type check after graph built). No ObjectInputFilter. Same sink in restoreMultiLayerNetworkAndNormalizer and restoreNormalizerFromInputStreamDeprecated.

Reproduce

  1. Java project with org.deeplearning4j:deeplearning4j-nn:1.0.0-M2.1 + org.nd4j:nd4j-native-platform:1.0.0-M2.1.
  2. Build baseline.zip via ModelSerializer.writeModel(net, file, true).
  3. Build edgecase.zip = baseline + appended preprocessor.bin = ObjectOutputStream of the nested structure above (List of 2000 HashMaps×400 + 300-deep Map chain).
  4. ModelSerializer.restoreMultiLayerNetwork(new File("edgecase.zip")) with -Xmx256mOutOfMemoryError during deserialization.
  5. Confirm no integrity gate: javap -p -c org.deeplearning4j.util.ModelSerializer.

Remediation

Wrap the preprocessor/normalizer deserialization in a strict ObjectInputFilter allowlist (limit to expected DataSetPreProcessor types, with maxdepth/maxrefs/maxbytes); add per-entry and total-size caps in loadZipData; prefer a data-only format over native Java serialization for model metadata; optionally verify a checksum/signature before deserializing.

Note on scanner coverage

Protect AI's ModelScan does not currently cover the DL4J format, so this malicious model file passes the safety scan undetected.

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