{"id":"GHSA-7gcf-g7xr-8hxj","title":"serde_with: KeyValueMap serialization panics on empty sequence or map entries","summary":"serde_with: KeyValueMap serialization panics on empty sequence or map entries","severity":"medium","cwe":["CWE-20"],"vendor":"serde_with","product":"serde_with","ecosystem":"rust","affected":["serde_with < 3.21.0"],"patched":["serde_with 3.21.0"],"published":"2026-07-15","updated":"2026-07-15","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-7gcf-g7xr-8hxj","references":[{"url":"https://github.com/jonasbb/serde_with/security/advisories/GHSA-7gcf-g7xr-8hxj"},{"url":"https://github.com/jonasbb/serde_with/pull/966"},{"url":"https://github.com/jonasbb/serde_with/commit/c8a1d820ea25df01692b367058d587343e199389"},{"url":"https://github.com/jonasbb/serde_with/releases/tag/v3.21.0"},{"url":"https://github.com/advisories/GHSA-7gcf-g7xr-8hxj"}],"tags":["ghsa","rust"],"ingestedAt":"2026-07-15T22:46:58.751Z","slug":"GHSA-7gcf-g7xr-8hxj","body":"## Overview\n\n### Summary\n\nThe public `KeyValueMap` serializer assumes that each mapped element has at least one field or item to use as the map key, but it subtracts `1` from the caller-visible length before validating that assumption. An application that serializes attacker-controlled data through `#[serde_as(as = \"KeyValueMap<_>\")]` can be crashed by an empty inner sequence or map entry.\n\n### Details\n\nThe affected public surface includes:\n\n- Serialization of `#[serde_as(as = \"KeyValueMap<_>\")]` values through `serde_json::to_string` or any other Serde serializer`\n- Public `KeyValueMap` conversions for sequence and map-backed entries`\n\nThe root cause is: The `KeyValueMap` serializer preallocating `Vec::with_capacity(len - 1)` or `Vec::with_capacity(len.unwrap_or(17) - 1)` before checking that the element actually contains the required first key field or item.\n\nThe vulnerable data/control flow is: attacker-controlled empty entry -> `serde_json::to_string` -> `KeyValueMap<TAs>::serialize_as` -> `SeqAsMapSerializer::{serialize_seq,serialize_map}` -> `Vec::with_capacity(len - 1)` or `Vec::with_capacity(len.unwrap_or(17) - 1)` -> panic\n\nRelevant source locations:\n\n- `serde_with/src/key_value_map.rs:590`\n- `serde_with/src/key_value_map.rs:599`\n- `serde_with/src/key_value_map.rs:613`\n- `serde_with/src/key_value_map.rs:632`\n- `serde_with/src/key_value_map.rs:648`\n\n### PoC\n\n```rust\n/*\n[dependencies]\nserde = {version = \"*\", features = [\"derive\"]}\nserde_with = \"*\"\nserde_json = \"*\"\n*/\n\nuse serde::Serialize;\nuse serde_with::{serde_as, KeyValueMap};\n\n#[derive(Serialize)]\n#[serde(transparent)]\nstruct Seq(Vec<String>);\n\n#[serde_as]\n#[derive(Serialize)]\n#[serde(transparent)]\nstruct KVMap {\n    #[serde_as(as = \"KeyValueMap<_>\")]\n    foo: Vec<Seq>,\n}\n\nfn main() {\n    let value = KVMap {\n        foo: vec![Seq(Vec::new())],\n    };\n    let _ = serde_json::to_string(&value).unwrap();\n}\n```\n\n### Impact\n\nA local attacker who can trigger serialization of attacker-controlled data through `KeyValueMap` can terminate the process, causing a denial of service.\n\n## Affected packages\n\n- `serde_with < 3.21.0`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `serde_with 3.21.0`","depth":"sunlit","depthScore":28,"depthScoreParts":{"impact":27.5,"likelihood":0,"exploitation":0,"ransomware":0},"changes":[]}