Title: Arbitrary Code Execution via eval() in keras_hub.tokenizers.RWKVTokenizer deserialized from .keras model file under safe_mode=True
Affected:keras-hub v0.27.1 (commit e8094ef, 2026-04-08)
File:keras_hub/src/models/rwkv7/rwkv7_tokenizer.py:117,275Severity: High (CVSS 8.8)
Root Cause
RWKVTokenizer.set_vocabulary() calls eval() on each vocabulary entry:
python
1# Line 275 — keras_hub/src/models/rwkv7/rwkv7_tokenizer.py2repr_str =eval(line[line.index(" "): line.rindex(" ")])
The vocabulary field is part of get_config() output and therefore embedded in .keras config.json files. When a malicious .keras file is loaded via keras.models.load_model() or keras.src.saving.serialization_lib.deserialize_keras_object(), the attacker-controlled vocabulary triggers eval() under default safe_mode=True.
Attack Vector
Attacker crafts a .keras file with malicious vocabulary entries
Victim loads the file: keras.models.load_model("malicious.keras")
RWKVTokenizer is deserialized via keras_hub>RWKVTokenizer registered name
Primary: Arbitrary code execution on any system that loads the malicious .keras file
Vector: Malicious .keras file distributed via HuggingFace Model Hub
Affected scope: Any user of keras + keras-hub who loads a model containing RWKVTokenizer
Stealth: No exception raised — the model appears to load correctly
CVE References
CVE-2025-9906 (JFrog): Identical pattern — keras.utils.get_file reachable via .keras deserialization. Fix: added to LOADING_APIS blocklist. Same mechanism, different gadget.
CVE-2025-49655: TorchModuleWrappertorch.load() via .keras deserialization. Fix: added safe_mode check to from_config.
CVE-2025-1550: keras_hub.layers.TFSMLayertf.saved_model.load() via .keras deserialization. Fix: safe_mode check in from_config.
This finding follows the same pattern as all three CVEs. RWKVTokenizer was added in commit e8094ef (2026-04-08) without the hardening applied to the above classes.
Suggested Fix
Replace eval() with ast.literal_eval() at rwkv7_tokenizer.py:117,275, and add a from_config override with safe_mode check to RWKVTokenizer:
python
1@classmethod2deffrom_config(cls, config,**kwargs):3from keras.src.saving import serialization_lib
4if serialization_lib.in_safe_mode()isnotFalse:5raise ValueError(6"Requested deserialization of RWKVTokenizer, which calls eval() "7"on vocabulary entries. This is disallowed by default. Pass "8"safe_mode=False to the loading function if you trust the source."9)10return cls(**config)