Benign MessagePack / RLlib Checkpoint Security PoC

This repository stages a safe proof-of-concept for a MessagePack-based ML checkpoint loading issue. The artifact is a tiny state.msgpack file that follows the Ray RLlib checkpoint state-file shape and carries a NumPy object-dtype array encoded through msgpack-numpy.

When decoded through Ray RLlib's restore_from_path() MessagePack path, the current msgpack-numpy decoder reaches pickle.loads() for object-dtype array data. The embedded payload only writes a local marker file named MSG_PACK_NUMPY_MARKER.txt.

Public PoC URL: https://huggingface.co/pragnyanramtha/rllib-msgpack-numpy-object-array-ace-poc

Files

  • state.msgpack - benign PoC checkpoint state file.
  • verify_poc.py - verifies plain MessagePack parsing, direct msgpack-numpy parsing, and Ray RLlib restore behavior.
  • build_poc.py - reproduces the artifact generation.
  • artifact_manifest.json - SHA256, size, and marker details.
  • results.json - local verification output.
  • scanner_output_file.json - ModelScan 0.8.8 output for state.msgpack.
  • scanner_output_dir.json - ModelScan 0.8.8 output for this staged folder.
  • requirements.txt - pinned reproduction dependencies used for this validation.

Tested Versions

  • Python 3.12.12
  • Ray 2.55.1
  • msgpack 1.1.2
  • msgpack-numpy 0.4.8
  • NumPy 2.4.4
  • ModelScan 0.8.8

Reproduction

python -m venv .venv
.venv/Scripts/python -m pip install -r requirements.txt
.venv/Scripts/python build_poc.py
.venv/Scripts/python verify_poc.py
.venv/Scripts/modelscan -p state.msgpack -r json -o scanner_output_file.json --show-skipped

On Linux/macOS, replace .venv/Scripts/python with .venv/bin/python.

Expected behavior:

  • Plain msgpack.load() parses the file as data and does not create the marker.
  • msgpack_numpy.load() creates MSG_PACK_NUMPY_MARKER.txt.
  • Ray RLlib Checkpointable.restore_from_path() creates MSG_PACK_NUMPY_MARKER.txt.
  • ModelScan 0.8.8 reports total_scanned: 0 and skips state.msgpack as SCAN_NOT_SUPPORTED.

Evidence Summary

Artifact:

SHA256: 3ddf739096ea87558f341e1705b607510e7e7f3af4c37841b51bd8809b52e465
Size: 506 bytes

Runtime:

"ray_rllib_restore_check": {
  "restored_keys": ["format", "object_array", "safe_weights"],
  "object_array_type": "ndarray",
  "object_array_repr": "array([34], dtype=object)",
  "marker_created": true,
  "marker_text": "msgpack_numpy_object_array_marker\n"
}

Scanner:

"scanned": {"total_scanned": 0},
"skipped": {
  "total_skipped": 1,
  "skipped_files": [{
    "category": "SCAN_NOT_SUPPORTED",
    "description": "Model Scan did not scan file",
    "source": "state.msgpack"
  }]
}

Why This Is ML-Format Relevant

Ray RLlib documents checkpoints as model/training artifacts that can be saved to local disk or cloud storage and restored through restore_from_path() / from_checkpoint(). The docs state that checkpoint directories contain a pickle or msgpack state file, and current RLlib source loads state.msgpack with a msgpack module patched by msgpack-numpy.

Primary references:

Security Impact

An attacker-controlled RLlib .msgpack checkpoint state file can trigger arbitrary Python execution when a victim restores the checkpoint through RLlib's MessagePack path. This PoC uses a harmless local marker write, but the primitive is Python pickle execution hidden inside a MessagePack/NumPy serialization layer.

Limitations:

  • This is not a native parser memory-corruption issue.
  • It requires a victim workflow that restores an untrusted Ray RLlib MessagePack checkpoint or otherwise decodes the artifact through msgpack-numpy.
  • The scanner evidence is a ModelScan unsupported-format gap for a dangerous .msgpack artifact, not a claim that every Hugging Face scanner accepts the file as clean.

Mitigations

  • Do not restore untrusted RLlib MessagePack checkpoints.
  • Reject or sanitize object-dtype arrays during MessagePack checkpoint restore.
  • Avoid msgpack_numpy.patch() for untrusted checkpoint data, or make the object-dtype pickle path opt-in only.
  • Add scanner support for .msgpack model artifacts that recursively detects nested pickle payloads in msgpack-numpy object-array records.
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