Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 174 additions & 0 deletions SPECS/keras/CVE-2026-1669.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
From e24a3c620061070910de069ad5eed298241bbc9d Mon Sep 17 00:00:00 2001
From: AllSpark <allspark@microsoft.com>
Date: Tue, 14 Apr 2026 10:18:35 +0000
Subject: [PATCH] Do not allow external links in HDF5 files; verify
group/dataset; remove unverified items/values; adjust failed_saveables
handling

Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: AI Backport of https://github.com/keras-team/keras/commit/8a37f9dadd8e23fa4ee3f537eeb6413e75d12553.patch
---
keras/src/saving/saving_lib.py | 72 ++++++++++++++++++----------------
1 file changed, 39 insertions(+), 33 deletions(-)

diff --git a/keras/src/saving/saving_lib.py b/keras/src/saving/saving_lib.py
index 0bcce01..fe5eb10 100644
--- a/keras/src/saving/saving_lib.py
+++ b/keras/src/saving/saving_lib.py
@@ -413,7 +413,8 @@ def _load_state(
try:
saveable.load_own_variables(weights_store.get(inner_path))
except Exception as e:
- failed_saveables.add(id(saveable))
+ if failed_saveables is not None:
+ failed_saveables.add(id(saveable))
error_msgs[id(saveable)] = saveable, e
failure = True
else:
@@ -424,7 +425,8 @@ def _load_state(
try:
saveable.load_assets(assets_store.get(inner_path))
except Exception as e:
- failed_saveables.add(id(saveable))
+ if failed_saveables is not None:
+ failed_saveables.add(id(saveable))
error_msgs[id(saveable)] = saveable, e
failure = True
else:
@@ -472,7 +474,7 @@ def _load_state(
if not failure:
if visited_saveables is not None and newly_failed <= 0:
visited_saveables.add(id(saveable))
- if id(saveable) in failed_saveables:
+ if failed_saveables is not None and id(saveable) in failed_saveables:
failed_saveables.remove(id(saveable))
error_msgs.pop(id(saveable))

@@ -657,10 +659,12 @@ class H5Entry:
else:
found = False
if not path:
- self.group = self.h5_file["vars"]
+ self.group = self._verify_group(self.h5_file["vars"])
found = True
elif path in self.h5_file and "vars" in self.h5_file[path]:
- self.group = self.h5_file[path]["vars"]
+ self.group = self._verify_group(
+ self._verify_group(self.h5_file[path])["vars"]
+ )
found = True
else:
# No hit.
@@ -671,22 +675,43 @@ class H5Entry:
)
self.path = path
if path in self.h5_file and "vars" in self.h5_file[path]:
- self.group = self.h5_file[path]["vars"]
+ self.group = self._verify_group(
+ self._verify_group(self.h5_file[path])["vars"]
+ )
found = True
if not found:
self.group = {}

+ def _verify_group(self, group):
+ if not isinstance(group, h5py.Group):
+ raise ValueError(
+ f"Invalid H5 file, expected Group but received {type(group)}"
+ )
+ return group
+
+ def _verify_dataset(self, dataset):
+ if not isinstance(dataset, h5py.Dataset):
+ raise ValueError(
+ f"Invalid H5 file, expected Dataset, received {type(dataset)}"
+ )
+ # Disallow external links
+ try:
+ external = dataset.external
+ except Exception:
+ external = False
+ if external:
+ raise ValueError(
+ "Not allowed: H5 file Dataset with external links: "
+ f"{dataset.external}"
+ )
+ return dataset
+
def __len__(self):
return self.group.__len__()

def keys(self):
return self.group.keys()

- def items(self):
- return self.group.items()
-
- def values(self):
- return self.group.values()

def __setitem__(self, key, value):
if self.mode != "w":
@@ -700,56 +725,37 @@ class H5Entry:

def __getitem__(self, name):
value = self.group[name]
-
- # ------------------------------------------------------
- # CASE 2 — HDF5 DATASET → SAFE LOADING
- # ------------------------------------------------------
-
- # Skip any objects that are not proper datasets
+ # Not a dataset: try to read scalar content if possible
if not hasattr(value, "shape") or not hasattr(value, "dtype"):
- # Fallback: attempt read if possible, else return as-is
try:
return value[()]
except Exception:
return value
-
+ # Verify dataset and disallow external links
+ value = self._verify_dataset(value)
shape = value.shape
dtype = value.dtype
-
- # ------------------------------------------------------
- # Validate SHAPE (avoid malformed / malicious metadata)
- # ------------------------------------------------------
-
# No negative dimensions
if any(dim < 0 for dim in shape):
raise ValueError(
"Malformed HDF5 dataset shape encountered in .keras file; "
"negative dimension detected."
)
-
# Prevent absurdly high-rank tensors
if len(shape) > 64:
raise ValueError(
"Malformed HDF5 dataset shape encountered in .keras file; "
"tensor rank exceeds safety limit."
)
-
# Safe product computation (Python int is unbounded)
num_elems = int(np.prod(shape))
-
- # ------------------------------------------------------
# Validate TOTAL memory size
- # ------------------------------------------------------
size_bytes = num_elems * dtype.itemsize
if size_bytes > MAX_BYTES:
raise ValueError(
f"HDF5 dataset too large to load safely "
f"({size_bytes} bytes; limit is {MAX_BYTES})."
)
-
- # ------------------------------------------------------
- # SAFE — load dataset (guaranteed ≤ 4 GiB)
- # ------------------------------------------------------
arr = value[()]
if "dtype" in value.attrs and value.attrs["dtype"] == "bfloat16":
arr = np.array(arr, dtype=ml_dtypes.bfloat16)
--
2.45.4

6 changes: 5 additions & 1 deletion SPECS/keras/keras.spec
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Summary: Keras is a high-level neural networks API.
Name: keras
Version: 3.3.3
Release: 6%{?dist}
Release: 7%{?dist}
License: ASL 2.0
Vendor: Microsoft Corporation
Distribution: Azure Linux
Expand All @@ -17,6 +17,7 @@ Patch02: CVE-2025-8747.patch
Patch03: CVE-2025-9905.patch
Patch4: CVE-2025-12060.patch
Patch5: CVE-2026-0897.patch
Patch6: CVE-2026-1669.patch

# Fix for CVE-2025-9906 included as part of CVE-2025-8747 and kept here as nopatch
# and commented out, because from patch command perspective, these files
Expand Down Expand Up @@ -81,6 +82,9 @@ python3 pip_build.py --install


%changelog
* Tue Apr 14 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 3.3.3-7
- Patch for CVE-2026-1669

* Fri Jan 16 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 3.3.3-6
- Patch for CVE-2026-0897

Expand Down
Loading