ANT-2026-MAPZGQDY · jsoncons

heap-buffer-overflow high

Severity Claude high · Security research firm high · Maintainer -

Discovered by Claude Mythos Preview

REPORT

Anthropic's analysis, sealed at approval. Disclosure to the maintainer was performed by Ada Logics.

ANT-2026-MAPZGQDY: Heap-buffer-overflow in bigint.hpp:260

During a basic_bigint modulo operation (operator%), the nested divide → unnormalize → divide call chain invokes resize/reserve on the internal storage. The reserve function at bigint.hpp:257 allocates a heap region of only 1 byte, then at bigint.hpp:260 calls memcpy to copy 32 bytes into that region, writing 31 bytes out of bounds. This appears to be a size-calculation error — likely allocating N bytes instead of N * sizeof(unsigned long), or a wraparound in the capacity computation — that an attacker can trigger by supplying crafted bigint operands to the modulo operator.

Target

Project: jsoncons
Location: bigint.hpp:260

Technical Details

ASAN: "WRITE of size 32 at 0x7526765e0091 ... located 0 bytes after 1-byte region". The allocation stack and crash stack both land in the same reserve() call: line 257 allocates via allocator_traits::allocate, line 260 memcpy's into it. A 1-byte allocation for a container of unsigned long (8 bytes each) is impossible if the element count is correctly multiplied by sizeof(T), so the capacity argument reaching allocate() has been miscomputed or truncated — yet the subsequent memcpy uses the original (larger) length, producing a 32-byte heap OOB write.

Crash trace (truncated — full trace in attached crash.log):

INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 787429306
INFO: Loaded 1 modules   (591 inline 8-bit counters): 591 [0x61bbc50e3058, 0x61bbc50e32a7), 
INFO: Loaded 1 PC tables (591 PCs): 591 [0x61bbc50e32a8,0x61bbc50e5798), 
/out/fuzz_bigint: Running 1 inputs 1 time(s) each.
Running: /tmp/poc
EXIT_CODE:1


=== ASAN Report ===
=================================================================
==27==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7526765e0091 at pc 0x61bbc4ff6b0e bp 0x7ffd397ae0e0 sp 0x7ffd397ad8a0
WRITE of size 32 at 0x7526765e0091 thread T0
    #0 0x61bbc4ff6b0d in __asan_memcpy /src/llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:63:3
    #1 0x61bbc503f218 in reserve /src/jsoncons/./include/jsoncons/utility/bigint.hpp:260:17
    #2 0x61bbc503f218 in jsoncons::detail::bigint_storage<std::__1::allocator<unsigned long>>::reserve(unsigned long) /src/jsoncons/./include/jsoncons/utility/bigint.hpp:461:27
    #3 0x61bbc503ec98 in jsoncons::detail::bigint_storage<std::__1::allocator<unsigned long>>::resize(unsigned long) /src/jsoncons/./include/jsoncons/utility/bigint.hpp:521:9
    #4 0x61bbc5042672 in resize /src/jsoncons/./include/jsoncons/utility/bigint.hpp:821:18
    #5 0x61bbc5042672 in jsoncons::basic_bigint<std::__1::allocator<unsigned long>>::divide(jsoncons::basic_bigint<std::__1::allocator<unsigned long>> const&, jsoncons::basic_bigint<std::__1::allocator<unsigned long>>&, jsoncons::basic_bigint<std::__1::allocator<unsigned long>>&, bool) const /src/jsoncons/./include/jsoncons/utility/bigint.hpp:1668:14
    #6 0x61bbc5044514 in operator/= /src/jsoncons/./include/jsoncons/utility/bigint.hpp:1034:9
    #7 0x61bbc5044514 in jsoncons::basic_bigint<std::__1::allocator<unsigned long>>::unnormalize(jsoncons::basic_bigint<std::__1::allocator<unsigned long>>&, int, bool) const /src/jsoncons/./include/jsoncons/utility/bigint.hpp:1832:17
    [... 30 more frames — full trace in crash.log]

Reproduction

  1. Construct two basic_bigint values whose division path reaches divide() → unnormalize() → divide() with a resize target that miscomputes in reserve()
  2. Invoke operator% on those operands
  3. reserve() at bigint.hpp:257 allocates a 1-byte buffer
  4. memcpy at bigint.hpp:260 writes 32 bytes past the allocation boundary

[No reproducer or sanitizer output attached — request from security-cvd@anthropic.com if needed.]

Acknowledgement

This vulnerability was discovered by Claude, Anthropic's AI assistant, and triaged by the Anthropic security team in collaboration with Anthropic Research. Please direct questions to security-cvd@anthropic.com and reference ANT-2026-MAPZGQDY.


Reference: ANT-2026-MAPZGQDY
Anthropic CVD Policy: https://www.anthropic.com/coordinated-vulnerability-disclosure

SECURITY RESEARCH FIRM ANALYSIS

Triage and disclosure were performed by Ada Logics.

Verdict
true positive
Severity
high
TIMELINE

Dates from discovery through public reveal.

  1. 2026-03-24 Reported to tracker
  2. 2026-05-13 Sent to maintainer
  3. 2026-05-13 Maintainer acknowledged
  4. 2026-06-07 Patch released
  5. 2026-08-17 Publicly revealed
PROVENANCE

SHA-3-512 hash:

dbb46766ab13fa61edb019733154bfa9ac89f9a90eea7296fcd1ff9911890f89fc91123d15a799782dd054c39a6cab451ac6e7637f86ff89a0e2714ce219462c

Committed 2026-05-13 10:55 PT

Revealed 2026-08-17 10:47 PT

Verify (download preimage.json)

Show preimage JSON
{
  "ant_id": "ANT-2026-MAPZGQDY",
  "bug_class": "Heap-buffer-overflow",
  "claude_severity": "high",
  "commit_sha": null,
  "created_at": "2026-03-24T18:30:02+00:00",
  "description": "During a basic_bigint modulo operation (operator%), the nested divide → unnormalize → divide call chain invokes resize/reserve on the internal storage. The reserve function at bigint.hpp:257 allocates a heap region of only 1 byte, then at bigint.hpp:260 calls memcpy to copy 32 bytes into that region, writing 31 bytes out of bounds. This appears to be a size-calculation error — likely allocating N bytes instead of N * sizeof(unsigned long), or a wraparound in the capacity computation — that an attacker can trigger by supplying crafted bigint operands to the modulo operator.",
  "discovered_at": null,
  "location": "bigint.hpp:260",
  "poc_sha256": null,
  "preimage_version": 1,
  "project": "jsoncons",
  "reproduction": [
    "Construct two basic_bigint values whose division path reaches divide() → unnormalize() → divide() with a resize target that miscomputes in reserve()",
    "Invoke operator% on those operands",
    "reserve() at bigint.hpp:257 allocates a 1-byte buffer",
    "memcpy at bigint.hpp:260 writes 32 bytes past the allocation boundary"
  ],
  "technical_details": "ASAN: \"WRITE of size 32 at 0x7526765e0091 ... located 0 bytes after 1-byte region\". The allocation stack and crash stack both land in the same reserve() call: line 257 allocates via allocator_traits::allocate, line 260 memcpy's into it. A 1-byte allocation for a container of unsigned long (8 bytes each) is impossible if the element count is correctly multiplied by sizeof(T), so the capacity argument reaching allocate() has been miscomputed or truncated — yet the subsequent memcpy uses the original (larger) length, producing a 32-byte heap OOB write.",
  "title": "Heap-buffer-overflow in bigint.hpp:260",
  "vendor_severity": "high"
}