--- license: apache-2.0 tags: - security - proof-of-concept - remote-code-execution --- # GluonTS `serde` deserialization RCE — proof of concept This repository is a **security proof of concept**. It demonstrates arbitrary code execution in [GluonTS](https://github.com/awslabs/gluon-ts) (`gluonts`, tested on **v0.16.3**) when a serialized predictor is loaded through the public `Predictor.deserialize(...)` API. GluonTS documents its `serde` format as a **human-readable, cross-version alternative to pickle**. However, `gluonts.core.serde.decode` resolves an arbitrary dotted class name from the JSON (`locate(...)`) and calls it with attacker-controlled arguments (`cls(*args, **kwargs)`), guarded only by an incomplete blocklist (`eval, exec, compile, open, input`). Any other callable — for example `os.system` — bypasses the check, so loading a crafted `predictor.json` runs commands. ## Files - `gluonts-config.json` — routes `Predictor.deserialize` to a `RepresentablePredictor`, whose `deserialize` reads `predictor.json` via `serde.load_json`. - `predictor.json` — the malicious payload: an `os.system` invocation. ## Reproduce ```bash pip install "gluonts==0.16.3" git clone https://huggingface.co/ gluonts-serde-poc cd gluonts-serde-poc # gluonts-config.json + predictor.json sit at the repository root python -c "from pathlib import Path; from gluonts.model.predictor import Predictor; Predictor.deserialize(Path('.'))" ls gluonts_serde_pwned.txt # marker created => code executed ``` `Predictor.deserialize(Path('.'))` loads the serialized predictor from this directory: it reads `gluonts-config.json`, routes to `MeanPredictor.deserialize`, which calls `serde.load_json` on `predictor.json` and thereby executes `os.system("echo pwned_by_gluonts_serde > gluonts_serde_pwned.txt")`. ## Safety The PoC is **benign**: the payload only writes a marker file (`gluonts_serde_pwned.txt`) into the current directory. It is not real malware. Replace the string to see that any command runs with the privileges of the loading process.