| --- |
| 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/<this-repo> 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. |
|
|