Security PoC β Remote Code Execution in synalinks via unsafe deserialization
This repository contains a proof-of-concept for a security vulnerability reported through
huntr (Model File Vulnerability program). It is published only as evidence
for responsible disclosure. The payload runs a harmless touch command. Do not load untrusted
synalinks artifacts on a machine you care about.
What this demonstrates
synalinks (PyPI 0.7.3 and current main) deserializes saved artifacts with its own copy of the
Keras serialization layer. Its loader _retrieve_class_or_fn imports an arbitrary Python module
and returns an arbitrary attribute named in the artifact, with no allowlist. This is the
exact pattern Keras fixed in CVE-2025-1550; synalinks did not port the fix.
The safe_mode=True default only blocks the __lambda__ path, not this one. So loading an
untrusted artifact (a saved Program, or a serialized reward/metric/tool) executes attacker-chosen
code with the default safe settings.
Files
malicious_reward.jsonβ the malicious artifact. Thefnfield uses the un-gated"function"import path to resolvesubprocess.Popen, sosafe_mode=Truedoes not block it.load_poc.pyβ loads the artifact through the public saving API and triggers the sink.
Reproduce
pip install synalinks # 0.7.3
python load_poc.py /tmp/PWNED # creates /tmp/PWNED via subprocess.Popen
ls -la /tmp/PWNED # file exists => arbitrary code executed
Expected output:
[*] loaded: RewardFunctionWrapper | fn = <class 'subprocess.Popen'>
-rw-r--r-- 1 user group 0 ... /tmp/PWNED
Root cause (and fix)
synalinks/src/saving/serialization_lib.py, _retrieve_class_or_fn:
mod = importlib.import_module(module) # attacker-controlled module, no allowlist
obj = vars(mod).get(name, None) # attacker-controlled attribute
Fix: restrict dynamic import to synalinks-owned packages and require the resolved object to be a
synalinks Saveable/registered type, as Keras now does. Optionally extend safe_mode to cover the
class/function import path, not only __lambda__.
Disclosure
Reported via huntr. CWE-502 / CWE-94. Same class as keras CVE-2025-1550, unfixed in this fork.