YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
PoC: Core ML .mlpackage path traversal β arbitrary file read (coremltools)
Proof-of-concept for a path-traversal / arbitrary-file-read vulnerability in the standard Core ML
model loader (apple/coremltools). Loading an untrusted .mlpackage lets the model file read an
arbitrary file from the victim's filesystem.
This repo is gated (manual review) and shared only with protectai-bot for huntr triage. The payload
is benign β it only reads /etc/passwd to demonstrate the out-of-bundle read; it never writes or executes.
Root cause
A .mlpackage is a directory bundle with a Manifest.json. Each item entry has a "path" field that
the loader joins to the bundle's Data/ directory without any containment check:
modelpackage/src/ModelPackage.cpp β ModelPackageImpl::findItem() (also lines 308 / 516):
auto path = m_packageDataDirPath / itemInfoEntry->getString(kModelPackageItemInfoPathKey); // "path"
std::filesystem::path::operator/ discards the left operand when the right operand is absolute, so a
Manifest "path" of /etc/passwd resolves to /etc/passwd; a ../-laden value traverses out of the
bundle. That escaped path flows to the Python loader and is opened directly:
coremltools/models/utils.py:
specfile = _ModelPackage(model_path).getRootModel().path() # :265
...
with open(specfile, "rb") as f: # :270
spec.ParseFromString(f.read())
Reproduce
pip install coremltools # tested on 9.0 (latest), Python 3.13
python verify_poc.py
Expected output:
Out-of-bundle files coremltools was made to open: ['/etc/passwd']
RESULT: *** PATH TRAVERSAL / ARBITRARY FILE READ CONFIRMED ***
verify_poc.py calls coremltools.utils.load_spec("poc.mlpackage") with an open() spy that records any
file opened outside the bundle. coremltools opens /etc/passwd β named only by the crafted
poc.mlpackage/Manifest.json "path" field. (load_spec then raises DecodeError because /etc/passwd
isn't a protobuf β but the unauthorized read has already happened. If the target is itself a serialized
Core ML protobuf, its full contents load into the returned spec.)
The same read also occurs via the public coremltools.models.MLModel("poc.mlpackage") API.
Impact
Opening/inspecting/converting an untrusted .mlpackage (a routinely shared/downloaded bundle) silently
reads an attacker-chosen file (absolute path or ../ traversal) from the victim's machine β info
disclosure / arbitrary file read, plus a file-existence oracle. In pipelines that re-serialize or serve
the loaded spec, this becomes content exfiltration.
Suggested fix
In ModelPackageImpl::findItem (and lines 308/516): reject absolute paths and .. components, resolve
with std::filesystem::weakly_canonical, and verify containment within m_packageDataDirPath before use.
Files
poc.mlpackage/β crafted Core ML package (Manifest"path"=/etc/passwd).verify_poc.pyβ benign reproducer with theopen()spy.