{"record":{"id":"0d08eb1c3fac4f9a","repo":"gchq/CyberChef","slug":"need-at-least-20-bytes-for-a-tcp-header","errorCode":null,"errorMessage":"Need at least 20 bytes for a TCP Header","messagePattern":"Need at least 20 bytes for a TCP Header","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/ParseTCP.mjs","lineNumber":61,"sourceCode":"    /**\n     * @param {string} input\n     * @param {Object[]} args\n     * @returns {html}\n     */\n    run(input, args) {\n        const format = args[0];\n\n        if (format === \"Hex\") {\n            input = fromHex(input);\n        } else if (format === \"Raw\") {\n            input = Utils.strToArrayBuffer(input);\n        } else {\n            throw new OperationError(\"Unrecognised input format.\");\n        }\n\n        const s = new Stream(new Uint8Array(input));\n        if (s.length < 20) {\n            throw new OperationError(\"Need at least 20 bytes for a TCP Header\");\n        }\n\n        // Parse Header\n        const TCPPacket = {\n            \"Source port\": s.readInt(2),\n            \"Destination port\": s.readInt(2),\n            \"Sequence number\": bytesToLargeNumber(s.getBytes(4)),\n            \"Acknowledgement number\": s.readInt(4),\n            \"Data offset\": s.readBits(4),\n            \"Flags\": {\n                \"Reserved\": toBinary(s.readBits(3), \"\", 3),\n                \"NS\": s.readBits(1),\n                \"CWR\": s.readBits(1),\n                \"ECE\": s.readBits(1),\n                \"URG\": s.readBits(1),\n                \"ACK\": s.readBits(1),\n                \"PSH\": s.readBits(1),\n                \"RST\": s.readBits(1),","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/ParseTCP.mjs#L43-L79","documentation":"Parse TCP needs at least 20 bytes because the fixed TCP header (source/dest port, seq, ack, offset, flags, window, checksum, urgent pointer) is exactly 20 bytes before options. After converting the input via the chosen format, the operation wraps it in a Stream and refuses to parse if fewer than 20 bytes remain, since reading the header fields would otherwise read past the buffer. This is a precondition guard, not a parse failure of a valid packet.","triggerScenarios":"Calling ParseTCP.run with input that decodes to < 20 bytes: a Hex string shorter than 40 hex chars, or a Raw string shorter than 20 characters. Also triggered when the wrong 'Input format' arg is selected so the bytes decode to a too-short buffer, or when a full Ethernet/IP frame is pasted instead of just the TCP segment.","commonSituations":"Pasting only the TCP payload without the L4 header; pasting a whole captured frame expecting the op to skip lower layers; selecting 'Raw' on hex data (or vice versa) so fromHex/strToArrayBuffer produces garbage of the wrong length; feeding a truncated packet capture.","solutions":["Supply at least 20 bytes of a TCP header (40 hex characters when 'Input format' is Hex).","Verify the 'Input format' arg matches your data: 'Hex' for hex strings, 'Raw' for binary rendered as text.","Strip Ethernet/IP/other lower-layer headers first so the input begins at the TCP header.","Confirm the bytes are actually a TCP segment (e.g. the IP protocol byte is 6) before handing them to this op."],"exampleFix":"// before: only payload / wrong layer\nrun(\"4500003c...\", [\"Hex\"])  // IP header -> too short as TCP\n\n// after: TCP header bytes starting at src port\nrun(\"0050c06f1f9bbee8...\", [\"Hex\"])  // >= 20 bytes of TCP","handlingStrategy":"validation","validationCode":"const FORMAT = args[0];\nconst bytes = FORMAT === \"Hex\" ? Buffer.from(input, \"hex\") : Buffer.from(input, \"latin1\");\nif (bytes.length < 20) throw new Error(`Need >= 20 bytes of TCP header, got ${bytes.length}`);\nreturn parseTcp.run(bytes.toString(\"latin1\"), args);","typeGuard":"function isTcpHeaderLength(format, input) {\n  const bytes = format === \"Hex\" ? Buffer.from(input, \"hex\") : Buffer.from(input, \"latin1\");\n  return bytes.length >= 20;\n}","tryCatchPattern":"try {\n  return parseTcp.run(input, [format]);\n} catch (e) {\n  if (e.message === \"Need at least 20 bytes for a TCP Header\") {\n    // surface a friendlier message, prompt for full header\n  }\n  throw e;\n}","preventionTips":["Validate decoded byte length >= 20 before calling.","Always set the Input format arg to match the data encoding.","Strip lower-layer headers upstream so the op receives only the TCP segment."],"tags":["networking","tcp","input-validation","length-check"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}