{"record":{"id":"0a693c631eeb9044","repo":"tursodatabase/turso","slug":"http-request-length-overflows-content-length","errorCode":null,"errorMessage":"HTTP request length overflows: {content_length}","messagePattern":"HTTP request length overflows: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"cli/sync_server.rs","lineNumber":1150,"sourceCode":"\n    let mut page = vec![0u8; PAGE_SIZE];\n    if conn.try_wal_watermark_read_page(1, &mut page, Some(max_frame))? {\n        Ok(db_size_from_page(&page) as u64)\n    } else {\n        Ok(0)\n    }\n}\n\nfn db_size_from_page(page: &[u8]) -> u32 {\n    u32::from_be_bytes(page[28..32].try_into().unwrap())\n}\n\n/// A client controls Content-Length, so the end of the body has to be\n/// computed without trusting it to fit.\nfn request_end(header_end: usize, content_length: usize) -> Result<usize> {\n    (header_end + 4)\n        .checked_add(content_length)\n        .ok_or_else(|| anyhow!(\"HTTP request length overflows: {content_length}\"))\n}\n\nfn find_header_end(data: &[u8], start: usize) -> Option<usize> {\n    (start..data.len().saturating_sub(3)).find(|&i| &data[i..i + 4] == b\"\\r\\n\\r\\n\")\n}\n\nfn parse_content_length(headers: &str) -> Option<usize> {\n    for line in headers.lines() {\n        let lower = line.to_lowercase();\n        if lower.starts_with(\"content-length:\") {\n            let value = line.split(':').nth(1)?.trim();\n            return value.parse().ok();\n        }\n    }\n    None\n}\n\nfn parse_http_request(data: &[u8]) -> Result<(String, String, Vec<u8>)> {","sourceCodeStart":1132,"sourceCodeEnd":1168,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/cli/sync_server.rs#L1132-L1168","documentation":"request_end computes header_end + 4 + content_length with checked arithmetic and returns this error when the sum overflows usize. Content-Length is fully client-controlled (the code comment says exactly this), so a hostile or broken client can send a value near usize::MAX and the body-end computation must not wrap. On 32-bit servers any Content-Length >= ~4 GiB also overflows.","triggerScenarios":"handle_connection calls request_end(header_end, content_length) after a client sends 'Content-Length: 18446744073709551615' or any value greater than usize::MAX - header_end - 4; on 32-bit builds, any legitimate-looking value >= 4 GiB triggers it.","commonSituations":"Port scanners and DoS tools probing the sync port with maximal header values; HTTP clients with integer-handling bugs that parse u64 and pass it through; 32-bit deployments receiving large uploads.","solutions":["Cap Content-Length at a sane maximum (e.g. 64 MiB) and answer 413/400 before computing the end offset.","Keep the checked arithmetic — never replace request_end with plain addition.","Close the connection on absurd lengths; a client sending usize::MAX is hostile or broken.","On 32-bit builds, remember values >= 4 GiB overflow usize even when they look plausible."],"exampleFix":"// before\nlet total_expected = request_end(header_end, content_length)?;\n\n// after\nconst MAX_BODY_BYTES: usize = 64 * 1024 * 1024;\nanyhow::ensure!(\n    content_length <= MAX_BODY_BYTES,\n    \"HTTP body of {content_length} bytes exceeds cap\"\n);\nlet total_expected = request_end(header_end, content_length)?;","handlingStrategy":"validation","validationCode":"const MAX_BODY_BYTES: usize = 64 * 1024 * 1024;\nfn content_length_acceptable(header_end: usize, content_length: usize) -> bool {\n    content_length <= MAX_BODY_BYTES\n        && (header_end + 4)\n            .checked_add(content_length)\n            .is_some()\n}\n// before computing the read target:\nanyhow::ensure!(\n    content_length_acceptable(header_end, content_length),\n    \"Content-Length {content_length} rejected\"\n);","typeGuard":"fn content_length_fits(header_end: usize, content_length: usize) -> bool {\n    (header_end + 4)\n        .checked_add(content_length)\n        .is_some()\n}","tryCatchPattern":"match request_end(header_end, content_length) {\n    Ok(total_expected) => { /* read until total_expected bytes */ }\n    Err(err) if err.to_string().contains(\"HTTP request length overflows\") => {\n        // hostile or broken client: answer 400/413 and close the connection\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Cap accepted Content-Length at a realistic maximum and enforce it before any allocation.","Never replace checked arithmetic with plain + when a client controls any operand.","Close connections that send near-usize::MAX lengths rather than just erroring.","Remember 32-bit servers overflow at 4 GiB, not usize::MAX."],"tags":["http","content-length","overflow","security","sync-server"],"backgroundTag":"http-content-length-overflow","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}