Hi, there is a buffer overflow (read) reachable with a crafted websocket partial payload in WebSocketParser.
#include <string>
#include "hv/WebSocketParser.h"
int main(){
WebSocketParser p;
// Optional: install a no-op callback to match typical usage
p.onMessage = [](int, const std::string&){};
// Minimal crashing buffer (first 49 bytes from the original input)
unsigned char data[49] = {
0,0,241,255,255,255,255,0,0,0,0,0,221,0,0,241,255,255,255,255,0,0,0,0,
255,0,255,0,243,243,243,243,243,243,243,0,241,255,255,255,255,255,255,255,
0,0,0,0,255
};
// Feeding 48 bytes causes websocket_parser_decode to read 1 byte past the end
p.FeedRecvData((const char*)data, 48);
return 0;
}
{
"Date": "2025-09-27T00:09:32.587003+00:00",
"Uname": "Linux 82d20f773412 5.15.0-140-generic #150-Ubuntu SMP Sat Apr 12 06:00:09 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux",
"OS": "Ubuntu",
"OSRelease": "22.04",
"Architecture": "amd64",
"ExecutablePath": "/tmp/tmpl2ejhjjc/reproducer",
"ProcEnviron": [
"LIBAFL_EDGES_MAP_SIZE=800000",
"PWD=/fuzz/workspace",
"CXX=gf_libafl_cxx",
"GRAPHFUZZ_USE_ASAN=1",
"HOME=/root",
"ASAN_OPTIONS=hard_rss_limit_mb=1024:detect_leaks=0",
"TERM=xterm-256color",
"SHLVL=1",
"LD_LIBRARY_PATH=/fuzz/install/lib",
"PATH=/root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"CC=gf_libafl_cc",
"DEBIAN_FRONTEND=noninteractive",
"OLDPWD=/fuzz/src",
"_=/usr/local/bin/agfi"
],
"ProcCmdline": "/tmp/tmpl2ejhjjc/reproducer",
"Stdin": "",
"ProcStatus": [],
"ProcMaps": [],
"ProcFiles": [],
"NetworkConnections": [],
"CrashSeverity": {
"Type": "NOT_EXPLOITABLE",
"ShortDescription": "stack-buffer-overflow(read)",
"Description": "Stack buffer overflow",
"Explanation": "The target reads data past the end, or before the beginning, of the intended stack buffer."
},
"Stacktrace": [
" #0 0x55555565dde1 in websocket_parser_decode /fuzz/src/http/websocket_parser.c:176:18",
" #1 0x55555565c079 in on_frame_body(websocket_parser*, char const*, unsigned long) /fuzz/src/http/WebSocketParser.cpp:33:9",
" #2 0x55555565cce3 in websocket_parser_execute /fuzz/src/http/websocket_parser.c:146:25",
" #3 0x55555565b691 in main /tmp/tmpl2ejhjjc/reproducer.cpp:17:7",
" #4 0x7ffff7a6dd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16",
" #5 0x7ffff7a6de3f in __libc_start_main csu/../csu/libc-start.c:392:3",
" #6 0x555555580344 in _start (/tmp/tmpl2ejhjjc/reproducer+0x2c344) (BuildId: daac15d9abbe898ffb7df81cf847401973489f50)"
],
"Registers": {},
"Disassembly": [],
"Package": "",
"PackageVersion": "",
"PackageArchitecture": "",
"PackageDescription": "",
"AsanReport": [
"==156==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffff5f00101 at pc 0x55555565dde2 bp 0x7fffffffe930 sp 0x7fffffffe928",
"READ of size 1 at 0x7ffff5f00101 thread T0",
" #0 0x55555565dde1 in websocket_parser_decode /fuzz/src/http/websocket_parser.c:176:18",
" #1 0x55555565c079 in on_frame_body(websocket_parser*, char const*, unsigned long) /fuzz/src/http/WebSocketParser.cpp:33:9",
" #2 0x55555565cce3 in websocket_parser_execute /fuzz/src/http/websocket_parser.c:146:25",
" #3 0x55555565b691 in main /tmp/tmpl2ejhjjc/reproducer.cpp:17:7",
" #4 0x7ffff7a6dd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16",
" #5 0x7ffff7a6de3f in __libc_start_main csu/../csu/libc-start.c:392:3",
" #6 0x555555580344 in _start (/tmp/tmpl2ejhjjc/reproducer+0x2c344) (BuildId: daac15d9abbe898ffb7df81cf847401973489f50)",
"",
"Address 0x7ffff5f00101 is located in stack of thread T0 at offset 257 in frame",
" #0 0x55555565b44f in main /tmp/tmpl2ejhjjc/reproducer.cpp:4",
"",
" This frame has 3 object(s):",
" [32, 64) 'ref.tmp.i'",
" [96, 176) 'p' (line 5)",
" [208, 257) 'data' (line 10) <== Memory access at offset 257 overflows this variable",
"HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork",
" (longjmp and C++ exceptions *are* supported)",
"SUMMARY: AddressSanitizer: stack-buffer-overflow /fuzz/src/http/websocket_parser.c:176:18 in websocket_parser_decode",
"Shadow bytes around the buggy address:",
" 0x7ffff5effe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x7ffff5efff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x7ffff5efff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x7ffff5f00000: f1 f1 f1 f1 f8 f8 f8 f8 f2 f2 f2 f2 00 00 00 00",
" 0x7ffff5f00080: 00 00 00 00 00 00 f2 f2 f2 f2 00 00 00 00 00 00",
"=>0x7ffff5f00100:[01]f3 f3 f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00",
" 0x7ffff5f00180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x7ffff5f00200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x7ffff5f00280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x7ffff5f00300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x7ffff5f00380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"Shadow byte legend (one shadow byte represents 8 application bytes):",
" Addressable: 00",
" Partially addressable: 01 02 03 04 05 06 07",
" Heap left redzone: fa",
" Freed heap region: fd",
" Stack left redzone: f1",
" Stack mid redzone: f2",
" Stack right redzone: f3",
" Stack after return: f5",
" Stack use after scope: f8",
" Global redzone: f9",
" Global init order: f6",
" Poisoned by user: f7",
" Container overflow: fc",
" Array cookie: ac",
" Intra object redzone: bb",
" ASan internal: fe",
" Left alloca redzone: ca",
" Right alloca redzone: cb",
"==156==ABORTING"
],
"MsanReport": [],
"UbsanReport": [],
"LuaReport": [],
"PythonReport": [],
"GoReport": [],
"JavaReport": [],
"RustReport": [],
"JsReport": [],
"CSharpReport": [],
"CrashLine": "/fuzz/src/http/websocket_parser.c:176:18",
"Source": [
" 172 ",
" 173 void websocket_parser_decode(char * dst, const char * src, size_t len, websocket_parser * parser) {",
" 174 size_t i = 0;",
" 175 for(; i < len; i++) {",
"--->176 dst[i] = src[i] ^ parser->mask[(i + parser->mask_offset) % 4];",
" 177 }",
" 178 ",
" 179 parser->mask_offset = (uint8_t) ((i + parser->mask_offset) % 4);",
" 180 }",
" 181 "
]
}
Hi, there is a buffer overflow (read) reachable with a crafted websocket partial payload in
WebSocketParser.Tested on
e2ba81ba.(found via automated fuzzing)
The following testcase demonstrates the issue:
testcase.cpp
crash report
{ "Date": "2025-09-27T00:09:32.587003+00:00", "Uname": "Linux 82d20f773412 5.15.0-140-generic #150-Ubuntu SMP Sat Apr 12 06:00:09 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux", "OS": "Ubuntu", "OSRelease": "22.04", "Architecture": "amd64", "ExecutablePath": "/tmp/tmpl2ejhjjc/reproducer", "ProcEnviron": [ "LIBAFL_EDGES_MAP_SIZE=800000", "PWD=/fuzz/workspace", "CXX=gf_libafl_cxx", "GRAPHFUZZ_USE_ASAN=1", "HOME=/root", "ASAN_OPTIONS=hard_rss_limit_mb=1024:detect_leaks=0", "TERM=xterm-256color", "SHLVL=1", "LD_LIBRARY_PATH=/fuzz/install/lib", "PATH=/root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "CC=gf_libafl_cc", "DEBIAN_FRONTEND=noninteractive", "OLDPWD=/fuzz/src", "_=/usr/local/bin/agfi" ], "ProcCmdline": "/tmp/tmpl2ejhjjc/reproducer", "Stdin": "", "ProcStatus": [], "ProcMaps": [], "ProcFiles": [], "NetworkConnections": [], "CrashSeverity": { "Type": "NOT_EXPLOITABLE", "ShortDescription": "stack-buffer-overflow(read)", "Description": "Stack buffer overflow", "Explanation": "The target reads data past the end, or before the beginning, of the intended stack buffer." }, "Stacktrace": [ " #0 0x55555565dde1 in websocket_parser_decode /fuzz/src/http/websocket_parser.c:176:18", " #1 0x55555565c079 in on_frame_body(websocket_parser*, char const*, unsigned long) /fuzz/src/http/WebSocketParser.cpp:33:9", " #2 0x55555565cce3 in websocket_parser_execute /fuzz/src/http/websocket_parser.c:146:25", " #3 0x55555565b691 in main /tmp/tmpl2ejhjjc/reproducer.cpp:17:7", " #4 0x7ffff7a6dd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16", " #5 0x7ffff7a6de3f in __libc_start_main csu/../csu/libc-start.c:392:3", " #6 0x555555580344 in _start (/tmp/tmpl2ejhjjc/reproducer+0x2c344) (BuildId: daac15d9abbe898ffb7df81cf847401973489f50)" ], "Registers": {}, "Disassembly": [], "Package": "", "PackageVersion": "", "PackageArchitecture": "", "PackageDescription": "", "AsanReport": [ "==156==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffff5f00101 at pc 0x55555565dde2 bp 0x7fffffffe930 sp 0x7fffffffe928", "READ of size 1 at 0x7ffff5f00101 thread T0", " #0 0x55555565dde1 in websocket_parser_decode /fuzz/src/http/websocket_parser.c:176:18", " #1 0x55555565c079 in on_frame_body(websocket_parser*, char const*, unsigned long) /fuzz/src/http/WebSocketParser.cpp:33:9", " #2 0x55555565cce3 in websocket_parser_execute /fuzz/src/http/websocket_parser.c:146:25", " #3 0x55555565b691 in main /tmp/tmpl2ejhjjc/reproducer.cpp:17:7", " #4 0x7ffff7a6dd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16", " #5 0x7ffff7a6de3f in __libc_start_main csu/../csu/libc-start.c:392:3", " #6 0x555555580344 in _start (/tmp/tmpl2ejhjjc/reproducer+0x2c344) (BuildId: daac15d9abbe898ffb7df81cf847401973489f50)", "", "Address 0x7ffff5f00101 is located in stack of thread T0 at offset 257 in frame", " #0 0x55555565b44f in main /tmp/tmpl2ejhjjc/reproducer.cpp:4", "", " This frame has 3 object(s):", " [32, 64) 'ref.tmp.i'", " [96, 176) 'p' (line 5)", " [208, 257) 'data' (line 10) <== Memory access at offset 257 overflows this variable", "HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork", " (longjmp and C++ exceptions *are* supported)", "SUMMARY: AddressSanitizer: stack-buffer-overflow /fuzz/src/http/websocket_parser.c:176:18 in websocket_parser_decode", "Shadow bytes around the buggy address:", " 0x7ffff5effe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", " 0x7ffff5efff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", " 0x7ffff5efff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", " 0x7ffff5f00000: f1 f1 f1 f1 f8 f8 f8 f8 f2 f2 f2 f2 00 00 00 00", " 0x7ffff5f00080: 00 00 00 00 00 00 f2 f2 f2 f2 00 00 00 00 00 00", "=>0x7ffff5f00100:[01]f3 f3 f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00", " 0x7ffff5f00180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", " 0x7ffff5f00200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", " 0x7ffff5f00280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", " 0x7ffff5f00300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", " 0x7ffff5f00380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", "Shadow byte legend (one shadow byte represents 8 application bytes):", " Addressable: 00", " Partially addressable: 01 02 03 04 05 06 07", " Heap left redzone: fa", " Freed heap region: fd", " Stack left redzone: f1", " Stack mid redzone: f2", " Stack right redzone: f3", " Stack after return: f5", " Stack use after scope: f8", " Global redzone: f9", " Global init order: f6", " Poisoned by user: f7", " Container overflow: fc", " Array cookie: ac", " Intra object redzone: bb", " ASan internal: fe", " Left alloca redzone: ca", " Right alloca redzone: cb", "==156==ABORTING" ], "MsanReport": [], "UbsanReport": [], "LuaReport": [], "PythonReport": [], "GoReport": [], "JavaReport": [], "RustReport": [], "JsReport": [], "CSharpReport": [], "CrashLine": "/fuzz/src/http/websocket_parser.c:176:18", "Source": [ " 172 ", " 173 void websocket_parser_decode(char * dst, const char * src, size_t len, websocket_parser * parser) {", " 174 size_t i = 0;", " 175 for(; i < len; i++) {", "--->176 dst[i] = src[i] ^ parser->mask[(i + parser->mask_offset) % 4];", " 177 }", " 178 ", " 179 parser->mask_offset = (uint8_t) ((i + parser->mask_offset) % 4);", " 180 }", " 181 " ] }