{"record":{"id":"180458353fbdf806","repo":"openai/codex","slug":"invalid-network-proxy-attribution-token-length","errorCode":null,"errorMessage":"invalid network proxy attribution token length","messagePattern":"invalid network proxy attribution token length","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"codex-rs/network-proxy/src/attribution.rs","lineNumber":96,"sourceCode":"        return Err(io::Error::new(io::ErrorKind::UnexpectedEof, \"empty proxy connection\").into());\n    }\n    if marker[0] != ATTRIBUTION_FRAME_MAGIC[0] {\n        return Ok(None);\n    }\n\n    let token = tokio::time::timeout(ATTRIBUTION_FRAME_TIMEOUT, async {\n        let mut magic = [0_u8; ATTRIBUTION_FRAME_MAGIC.len()];\n        stream.read_exact(&mut magic).await?;\n        if &magic != ATTRIBUTION_FRAME_MAGIC {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"invalid network proxy attribution frame\",\n            ));\n        }\n\n        let token_len = stream.read_u16().await? as usize;\n        if token_len == 0 || token_len > MAX_ATTRIBUTION_TOKEN_LEN {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"invalid network proxy attribution token length\",\n            ));\n        }\n        let mut token = vec![0_u8; token_len];\n        stream.read_exact(&mut token).await?;\n        String::from_utf8(token).map_err(|_| {\n            io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"network proxy attribution token is not UTF-8\",\n            )\n        })\n    })\n    .await\n    .map_err(|_| {\n        io::Error::new(\n            io::ErrorKind::TimedOut,\n            \"network proxy attribution frame timed out\",","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/network-proxy/src/attribution.rs#L78-L114","documentation":"The 8-byte magic matched, but the u16 length prefix that follows was 0 or exceeded MAX_ATTRIBUTION_TOKEN_LEN (128 bytes). Rejected with io::ErrorKind::InvalidData. Almost always a writer-side framing bug: wrong endianness (the reader uses tokio's read_u16, i.e. big-endian/network order; a little-endian writer sending a token of length 3 emits 0x0300 = 768), a shifted stream, or garbage after the magic.","triggerScenarios":"A hand-rolled frame writes the length little-endian or as u32 instead of big-endian u16; a truncated or interleaved first write shifts subsequent reads; the client sends the magic followed by unrelated bytes.","commonSituations":"Porting the preface to Python/Go where struct.pack/native little-endian is the default; test fixtures with hardcoded byte arrays drifting from the wire format; fuzzed input hitting the ingress.","solutions":["Use write_attribution_frame, which writes (token.len() as u16).to_be_bytes(), or replicate big-endian u16 exactly.","Write the whole frame with a single write_all so fields cannot interleave or shift.","Keep the token within 1..=128 bytes so the length prefix is valid by construction."],"exampleFix":"// before: little-endian length prefix\nwriter.write_all(&(token.len() as u16).to_le_bytes())?; // reader sees 0x0300 for len 3\n// after: big-endian, matching read_u16 network order\nwriter.write_all(&(token.len() as u16).to_be_bytes())?;","handlingStrategy":"validation","validationCode":"fn valid_attribution_frame_len(token: &str) -> bool {\n    let n = token.len();\n    n >= 1 && n <= 128 && u16::try_from(n).is_ok()\n}","typeGuard":"fn valid_attribution_frame_len(token: &str) -> bool {\n    (1..=128).contains(&token.len())\n}","tryCatchPattern":"Match io::ErrorKind::InvalidData whose message contains 'token length': dump the raw prefix bytes and verify the u16 is big-endian and equals the token length; a shifted stream means the earlier write was partial.","preventionTips":["Write the length as big-endian u16 (to_be_bytes), matching read_u16.","Emit magic + length + token in a single write_all.","In non-Rust ports, double-check struct.pack endianness ('>H', not '<H')."],"tags":["rust","codex","network-proxy","framing","length-prefix","invalid-data"],"backgroundTag":"invalid-length-prefix","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}