{"id":"CVE-2025-9906","aliases":["AZL-67508","DEBIAN-CVE-2025-9906","EUVD-2025-30281","GHSA-36fq-jgmw-4r9c","PYSEC-2025-76","UBUNTU-CVE-2025-9906"],"status":"published","title":"Arbitrary Code execution in Keras Safe Mode","description":"The Keras Model.load_model method can be exploited to achieve arbitrary code execution, even with safe_mode=True.\n\nOne can create a specially crafted .keras model archive that, when loaded via Model.load_model, will trigger arbitrary code to be executed. This is achieved by crafting a special config.json (a file within the .keras archive) that will invoke keras.config.enable_unsafe_deserialization() to disable safe mode. Once safe mode is disable, one can use the Lambda layer feature of keras, which allows arbitrary Python code in the form of pickled code. Both can appear in the same archive. Simply the keras.config.enable_unsafe_deserialization() needs to appear first in the archive and the Lambda with arbitrary code needs to be second.","severity":{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/AU:Y/R:A","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.00203,"percentile":0.10285,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-502"],"published":"2025-09-19T08:15:04Z","modified":"2026-11-05T05:40:51Z","fixes":[{"ecosystem":"PyPI","package":"keras","fixed_in":["3.11.0"],"sources":["ghsa","osv"]},{"ecosystem":"Azure Linux:3","package":"keras","fixed_in":["3.3.3-4"],"sources":["osv"]}],"affected":[{"source":"ghsa","ecosystem":"PyPI","package":"keras","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3.11.0"}]}]},{"source":"osv","ecosystem":"Azure Linux:3","package":"keras","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3.3.3-4"}]}]},{"source":"osv","ecosystem":"Debian:11","package":"keras","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.3.1+dfsg-3","2.3.1+dfsg2-1"]},{"source":"osv","ecosystem":"PyPI","package":"keras","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3.11.0"}]}],"versions":["0.2.0","0.3.0","0.3.1","0.3.2","0.3.3","1.0.0","1.0.1","1.0.2","1.0.3","1.0.4","1.0.5","1.0.6","1.0.7","1.0.8","1.1.0","1.1.1","1.1.2","1.2.0","1.2.1","1.2.2","2.0.0","2.0.1","2.0.2","2.0.3","2.0.4","2.0.5","2.0.6","2.0.7","2.0.8","2.0.9","2.1.0","2.1.1","2.1.2","2.1.3","2.1.4","2.1.5","2.1.6","2.10.0","2.10.0rc0","2.10.0rc1","2.11.0","2.11.0rc0","2.11.0rc1","2.11.0rc2","2.11.0rc3","2.12.0","2.12.0rc0","2.12.0rc1","2.13.1","2.13.1rc0","2.13.1rc1","2.14.0","2.14.0rc0","2.15.0","2.15.0rc0","2.15.0rc1","2.2.0","2.2.1","2.2.2","2.2.3","2.2.4","2.2.5","2.3.0","2.3.1","2.4.0","2.4.1","2.4.2","2.4.3","2.5.0rc0","2.6.0","2.6.0rc0","2.6.0rc1","2.6.0rc2","2.6.0rc3","2.7.0","2.7.0rc0","2.7.0rc2","2.8.0","2.8.0rc0","2.8.0rc1","2.9.0","2.9.0rc0","2.9.0rc1","2.9.0rc2","3.0.0","3.0.1","3.0.2","3.0.3","3.0.4","3.0.5","3.1.0","3.1.1","3.10.0","3.2.0","3.2.1","3.3.0","3.3.1","3.3.2","3.3.3","3.4.0","3.4.1","3.5.0","3.6.0","3.7.0","3.8.0","3.9.0","3.9.1","3.9.2"]},{"source":"osv","ecosystem":"PyPI","package":"keras"},{"source":"osv","ecosystem":"Ubuntu:18.04:LTS","package":"keras","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.0.7-2","2.1.1-1"]},{"source":"osv","ecosystem":"Ubuntu:20.04:LTS","package":"keras","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.2.4-1"]}],"products":[{"vendor":"google","product":"keras"},{"vendor":"keras","product":"keras"},{"vendor":"keras-team","product":"keras"}],"references":[{"url":"https://github.com/keras-team/keras/pull/21429","tags":["patch","Issue Tracking","fix","web","report"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2025-9906","tags":["web","advisory"]},{"url":"https://github.com/keras-team/keras/commit/713172ab56b864e59e2aa79b1a51b0e728bba858","tags":["web"]},{"url":"https://github.com/keras-team/keras/releases/tag/v3.11.0","tags":["web"]},{"url":"https://osv.dev/vulnerability/CVE-2025-9906","tags":["web"]},{"url":"https://github.com/pypa/advisory-database/tree/main/vulns/keras/PYSEC-2025-76.yaml","tags":["web"]},{"url":"https://github.com/advisories/GHSA-36fq-jgmw-4r9c","tags":["advisory"]},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2025/9xxx/CVE-2025-9906.json","tags":["advisory"]},{"url":"https://github.com/keras-team/keras","tags":["package"]},{"url":"https://security-tracker.debian.org/tracker/CVE-2025-9906","tags":["advisory"]},{"url":"https://ubuntu.com/security/CVE-2025-9906","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2025-9906","tags":["report"]}],"sources":{"cve":[{"id":"CVE-2025-9906","title":"Arbitrary Code execution in Keras Safe Mode","description":"The Keras Model.load_model method can be exploited to achieve arbitrary code execution, even with safe_mode=True.\n\nOne can create a specially crafted .keras model archive that, when loaded via Model.load_model, will trigger arbitrary code to be executed. This is achieved by crafting a special config.json (a file within the .keras archive) that will invoke keras.config.enable_unsafe_deserialization() to disable safe mode. Once safe mode is disable, one can use the Lambda layer feature of keras, which allows arbitrary Python code in the form of pickled code. Both can appear in the same archive. Simply the keras.config.enable_unsafe_deserialization() needs to appear first in the archive and the Lambda with arbitrary code needs to be second.","status":"published","published":"2025-09-19T08:15:04.349Z","modified":"2026-02-26T17:48:23.819Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/AU:Y/R:A","level":"high","assessor":"cna"}],"cwes":["CWE-502"],"updated_at":"2026-11-02T14:32:33.755525Z"}],"euvd":[{"id":"EUVD-2025-30281","description":"The Keras Model.load_model method can be exploited to achieve arbitrary code execution, even with safe_mode=True.\n\nOne can create a specially crafted .keras model archive that, when loaded via Model.load_model, will trigger arbitrary code to be executed. This is achieved by crafting a special config.json (a file within the .keras archive) that will invoke keras.config.enable_unsafe_deserialization() to disable safe mode. Once safe mode is disable, one can use the Lambda layer feature of keras, which allows arbitrary Python code in the form of pickled code. Both can appear in the same archive. Simply the keras.config.enable_unsafe_deserialization() needs to appear first in the archive and the Lambda with arbitrary code needs to be second.","status":"published","published":"2025-09-19T08:15:04Z","modified":"2026-02-26T17:48:23Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/AU:Y/R:A","level":"high"}],"updated_at":"2026-11-02T19:48:21.697838Z"}],"ghsa":[{"id":"GHSA-36fq-jgmw-4r9c","title":"Keras is vulnerable to Deserialization of Untrusted Data","description":"### Arbitrary Code Execution in Keras\n\nKeras versions prior to 3.11.0 allow for arbitrary code execution when loading a crafted `.keras` model archive, even when `safe_mode=True`.\n\nThe issue arises because the archive’s `config.json` is parsed before layer deserialization. This can invoke `keras.config.enable_unsafe_deserialization()`, effectively disabling safe mode from within the loading process itself. An attacker can place this call first in the archive and then include a `Lambda` layer whose function is deserialized from a pickle, leading to the execution of attacker-controlled Python code as soon as a victim loads the model file.\n\nExploitation requires a user to open an untrusted model; no additional privileges are needed. The fix in version 3.11.0 enforces safe-mode semantics *before* reading any user-controlled configuration and prevents the toggling of unsafe deserialization via the config file.\n\n**Affected versions:** \u003c 3.11.0\n**Patched version:** 3.11.0\n\nIt is recommended to upgrade to version 3.11.0 or later and to avoid opening untrusted model files.","status":"published","published":"2025-09-19T09:31:14Z","modified":"2026-05-29T20:51:09Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","level":"high"},{"version":"3.1","score":7.3,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-502"],"updated_at":"2026-11-02T14:40:15.638885Z"}],"nvd":[{"id":"CVE-2025-9906","description":"The Keras Model.load_model method can be exploited to achieve arbitrary code execution, even with safe_mode=True.\n\nOne can create a specially crafted .keras model archive that, when loaded via Model.load_model, will trigger arbitrary code to be executed. This is achieved by crafting a special config.json (a file within the .keras archive) that will invoke keras.config.enable_unsafe_deserialization() to disable safe mode. Once safe mode is disable, one can use the Lambda layer feature of keras, which allows arbitrary Python code in the form of pickled code. Both can appear in the same archive. Simply the keras.config.enable_unsafe_deserialization() needs to appear first in the archive and the Lambda with arbitrary code needs to be second.","status":"published","published":"2025-09-19T09:15:36.353Z","modified":"2026-10-19T16:10:00.26Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:Y/R:A/V:X/RE:X/U:X","level":"high","assessor":"secondary"},{"version":"3.1","score":7.3,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H","level":"high","assessor":"primary"}],"cwes":["CWE-502"],"updated_at":"2026-11-02T14:11:30.865098Z"}],"osv":[{"id":"CVE-2025-9906","title":"Arbitrary Code execution in Keras Safe Mode","description":"The Keras Model.load_model method can be exploited to achieve arbitrary code execution, even with safe_mode=True.\n\nOne can create a specially crafted .keras model archive that, when loaded via Model.load_model, will trigger arbitrary code to be executed. This is achieved by crafting a special config.json (a file within the .keras archive) that will invoke keras.config.enable_unsafe_deserialization() to disable safe mode. Once safe mode is disable, one can use the Lambda layer feature of keras, which allows arbitrary Python code in the form of pickled code. Both can appear in the same archive. Simply the keras.config.enable_unsafe_deserialization() needs to appear first in the archive and the Lambda with arbitrary code needs to be second.","status":"published","published":"2025-09-19T08:15:04.349Z","modified":"2026-10-28T02:30:27.868505194Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/AU:Y/R:A","level":"high"}],"cwes":["CWE-502"],"updated_at":"2026-11-02T15:44:53.490346Z"},{"id":"DEBIAN-CVE-2025-9906","description":"The Keras Model.load_model method can be exploited to achieve arbitrary code execution, even with safe_mode=True.  One can create a specially crafted .keras model archive that, when loaded via Model.load_model, will trigger arbitrary code to be executed. This is achieved by crafting a special config.json (a file within the .keras archive) that will invoke keras.config.enable_unsafe_deserialization() to disable safe mode. Once safe mode is disable, one can use the Lambda layer feature of keras, which allows arbitrary Python code in the form of pickled code. Both can appear in the same archive. Simply the keras.config.enable_unsafe_deserialization() needs to appear first in the archive and the Lambda with arbitrary code needs to be second.","status":"published","published":"2025-09-19T09:15:36.353Z","modified":"2026-08-27T23:05:46.91568783Z","cvss":[{"version":"3.1","score":7.3,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"updated_at":"2026-11-02T15:45:48.440897Z"},{"id":"GHSA-36fq-jgmw-4r9c","title":"Keras is vulnerable to Deserialization of Untrusted Data","description":"### Arbitrary Code Execution in Keras\n\nKeras versions prior to 3.11.0 allow for arbitrary code execution when loading a crafted `.keras` model archive, even when `safe_mode=True`.\n\nThe issue arises because the archive’s `config.json` is parsed before layer deserialization. This can invoke `keras.config.enable_unsafe_deserialization()`, effectively disabling safe mode from within the loading process itself. An attacker can place this call first in the archive and then include a `Lambda` layer whose function is deserialized from a pickle, leading to the execution of attacker-controlled Python code as soon as a victim loads the model file.\n\nExploitation requires a user to open an untrusted model; no additional privileges are needed. The fix in version 3.11.0 enforces safe-mode semantics *before* reading any user-controlled configuration and prevents the toggling of unsafe deserialization via the config file.\n\n**Affected versions:** \u003c 3.11.0\n**Patched version:** 3.11.0\n\nIt is recommended to upgrade to version 3.11.0 or later and to avoid opening untrusted model files.","status":"published","published":"2025-09-19T09:31:14Z","modified":"2026-09-10T03:50:27.820239587Z","cvss":[{"version":"3.1","score":7.3,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H","level":"high"},{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-502"],"updated_at":"2026-11-02T15:46:35.406455Z"},{"id":"PYSEC-2025-76","description":"The Keras Model.load_model method can be exploited to achieve arbitrary code execution, even with safe_mode=True.\n\nOne can create a specially crafted .keras model archive that, when loaded via Model.load_model, will trigger arbitrary code to be executed. This is achieved by crafting a special config.json (a file within the .keras archive) that will invoke keras.config.enable_unsafe_deserialization() to disable safe mode. Once safe mode is disable, one can use the Lambda layer feature of keras, which allows arbitrary Python code in the form of pickled code. Both can appear in the same archive. Simply the keras.config.enable_unsafe_deserialization() needs to appear first in the archive and the Lambda with arbitrary code needs to be second.","status":"published","published":"2025-09-19T09:15:36.353Z","modified":"2026-06-10T17:01:52.099728122Z","cvss":[{"version":"3.1","score":7.3,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"updated_at":"2026-11-02T15:52:54.242332Z"},{"id":"UBUNTU-CVE-2025-9906","description":"The Keras Model.load_model method can be exploited to achieve arbitrary code execution, even with safe_mode=True. One can create a specially crafted .keras model archive that, when loaded via Model.load_model, will trigger arbitrary code to be executed. This is achieved by crafting a special config.json (a file within the .keras archive) that will invoke keras.config.enable_unsafe_deserialization() to disable safe mode. Once safe mode is disable, one can use the Lambda layer feature of keras, which allows arbitrary Python code in the form of pickled code. Both can appear in the same archive. Simply the keras.config.enable_unsafe_deserialization() needs to appear first in the archive and the Lambda with arbitrary code needs to be second.","status":"published","published":"2025-09-19T09:15:00Z","modified":"2025-10-24T05:16:35Z","cvss":[{"version":"4.0","score":8.6,"vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/AU:Y/R:A","level":"high"},{"version":"3.1","score":7.3,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"updated_at":"2026-11-02T16:55:58.519486Z"},{"id":"AZL-67508","title":"CVE-2025-9906 affecting package keras for versions less than 3.3.3-4","description":"The Keras Model.load_model method can be exploited to achieve arbitrary code execution, even with safe_mode=True.\n\nOne can create a specially crafted .keras model archive that, when loaded via Model.load_model, will trigger arbitrary code to be executed. This is achieved by crafting a special config.json (a file within the .keras archive) that will invoke keras.config.enable_unsafe_deserialization() to disable safe mode. Once safe mode is disable, one can use the Lambda layer feature of keras, which allows arbitrary Python code in the form of pickled code. Both can appear in the same archive. Simply the keras.config.enable_unsafe_deserialization() needs to appear first in the archive and the Lambda with arbitrary code needs to be second.","status":"published","published":"2025-09-19T09:15:36Z","modified":"2026-11-05T05:40:51Z","updated_at":"2026-11-05T16:41:23.994498Z"}]}}
