ANT-2026-MAPZGQDY · jsoncons
heap-buffer-overflow high
Severity Claude high · Security research firm high · Maintainer -
Discovered by Claude Mythos Preview
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
- 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
[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
Triage and disclosure were performed by Ada Logics.
- Verdict
- true positive
- Severity
- high
Dates from discovery through public reveal.
- 2026-03-24 Reported to tracker
- 2026-05-13 Sent to maintainer
- 2026-05-13 Maintainer acknowledged
- 2026-06-07 Patch released
- 2026-08-17 Publicly revealed
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"
}