WebAssembly / WebAssembly/binaryen

heap-buffer-overflow in wasm::WATParser::Lexer::peek() at parser/lexer.h:137 (main branch @3ef8d19)

Open
#8,632 0 comments 0 reactions 1 assignee View on GitHub

@tlively is already working on this.

Since Apr 21, 2026.

Dominant language
WebAssembly
Stars
8.6k
Forks
885
Avg merge
1d 19h
Merged PRs (30d)
69

Description

Summary

ASan detects a heap-buffer-overflow (out-of-bounds read) in the WAT parser when parsing malformed input with wasm-ctor-eval.

Affected Version

  • Branch: main
  • Commit: 3ef8d19 (2026-04-21 latest)
  • Tool: wasm-ctor-eval
  • Build type: Debug + AddressSanitizer

Reproduction

mkdir build && cd build

cmake \
  -DCMAKE_C_COMPILER=/home/AFLplusplus/afl-clang-fast \
  -DCMAKE_CXX_COMPILER=/home/AFLplusplus/afl-clang-fast++ \
  -DCMAKE_C_FLAGS="-O0 -g -fno-omit-frame-pointer -fsanitize=address -Wno-error" \
  -DCMAKE_CXX_FLAGS="-std=c++20 -O0 -g -fno-omit-frame-pointer -fsanitize=address -Wno-bitwise-instead-of-logical -Wno-ambiguous-reversed-operator -Wno-error" \
  -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address -no-pie -pthread -ldl -lm" \
  -DCMAKE_BUILD_TYPE=Debug \
  -DBUILD_TESTS=OFF \
  -DBUILD_TOOLS=ON \
  -DENABLE_BYESAN=OFF \
  ..

make -j$(nproc)

./wasm-ctor-eval poc

ASan Error Log

==3262527==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60b000001549 at pc 0x7ffff5e55cce bp 0x7fffffff7650 sp 0x7fffffff7648
READ of size 1 at 0x60b000001549 thread T0
    #0 0x7ffff5e55ccd in wasm::WATParser::Lexer::peek() const /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/parser/lexer.h:137:33
    #1 0x7ffff5e5d5fa in wasm::WATParser::Lexer::takeHexdigit() /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/parser/lexer.h:561:28
    #2 0x7ffff5e59c82 in wasm::WATParser::Lexer::takeStr() /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/parser/lexer.h:905:25
    #3 0x7ffff5e469ab in wasm::WATParser::Lexer::takeString[abi:cxx11]() /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/parser/lexer.h:457:18
    #4 0x7ffff5e43ed4 in wasm::WATParser::ParseDeclsCtx::skipFunctionBody() /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/parser/context-decls.cpp:334:12
    #5 0x7ffff5eb181a in wasm::MaybeResult<wasm::Ok> wasm::WATParser::func<wasm::WATParser::ParseDeclsCtx>(wasm::WATParser::ParseDeclsCtx&) /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/parser/parsers.h:3509:19
    #6 0x7ffff5ea5e8c in wasm::MaybeResult<wasm::Ok> wasm::WATParser::modulefield<wasm::WATParser::ParseDeclsCtx>(wasm::WATParser::ParseDeclsCtx&) /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/parser/parsers.h:4030:18
    #7 0x7ffff5ea4683 in wasm::Result<wasm::Ok, wasm::Err> wasm::WATParser::moduleBody<wasm::WATParser::ParseDeclsCtx>(wasm::WATParser::ParseDeclsCtx&) /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/parser/parsers.h:4071:23
    #8 0x7ffff5ea3df5 in wasm::Result<wasm::Ok, wasm::Err> wasm::WATParser::module<wasm::WATParser::ParseDeclsCtx>(wasm::WATParser::ParseDeclsCtx&) /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/parser/parsers.h:4089:3
    #9 0x7ffff5ea3972 in wasm::WATParser::parseModule(wasm::WATParser::ParseDeclsCtx&) /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/parser/parse-1-decls.cpp:21:53
    #10 0x7ffff673099b in wasm::WATParser::(anonymous namespace)::doParseModule(wasm::Module&, wasm::WATParser::Lexer&, bool) /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/parser/wat-parser.cpp:114:3
    #11 0x7ffff6730409 in wasm::WATParser::parseModule(wasm::Module&, std::basic_string_view<char, std::char_traits<char> >, std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >) /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/parser/wat-parser.cpp:133:10
    #12 0x7ffff6b5d6cd in wasm::readTextData(std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, wasm::Module&, wasm::IRProfile) /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/wasm/wasm-io.cpp:41:21
    #13 0x7ffff6b5d138 in wasm::ModuleReader::readText(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, wasm::Module&) /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/wasm/wasm-io.cpp:50:3
    #14 0x7ffff6b5f893 in wasm::ModuleReader::read(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, wasm::Module&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/wasm/wasm-io.cpp:108:5
    #15 0x46174d in main /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/tools/wasm-ctor-eval.cpp:1592:14

0x60b000001549 is located 0 bytes to the right of 105-byte region [0x60b0000014e0,0x60b000001549)
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/new-cases/binaryen/latestest-04.21/binaryen-main/src/parser/lexer.h:137:33 in wasm::WATParser::Lexer::peek() const

Root Cause

Out-of-bounds read in peek() at lexer.h:137 when parsing unterminated/corrupted string literals.
The lexer does not check bounds before reading the next character during escape/hex parsing.

Call chain:

takeString() → takeStr() → takeHexdigit() → peek()

PoC

poc

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.