This repository contains a benign Core ML package proof for coremltools==9.0.
The PoC does not execute code, persist state, access credentials, or make network calls. It demonstrates that a model package can carry a symlink that is dereferenced when the package is loaded and re-saved.
Summary
The model package symlink_lfi.mlpackage is otherwise loadable, but it contains an extra symlink inside the package:
That target is outside the .mlpackage directory but inside this cloned repository. When a consumer loads the package with coremltools.models.MLModel(..., skip_model_load=True) and re-saves it with MLModel.save(), coremltools copies the symlink target contents into the output package as a regular file.
Affected Format
Format: Core ML package (.mlpackage)
Tested target: coremltools==9.0
Trigger path: coremltools.models.MLModel(..., skip_model_load=True) followed by MLModel.save(...)
Impact class: local file inclusion / unintended file copy during package re-save
Security Impact
An untrusted .mlpackage can include a symlink in a package subdirectory. A workflow that clones or downloads the package preserving symlinks, loads it with coremltools, and re-saves it can copy the symlink target into the output model package as ordinary file contents. This can disclose files reachable from the package path into a generated model artifact.
This PoC uses a harmless repository-local marker file for portability. It does not attempt to read secrets or system files.
The --git-check mode initializes a local git repository from this folder, commits the package, clones it, verifies that git preserves the symlink as mode 120000, and repeats the Core ML save proof from the clone.
This is a local-file disclosure/copy primitive during model package re-save, not arbitrary code execution. The staged symlink is relative for reviewer portability; separate lab evidence also verifies absolute symlinks and symlinked directories.