[GH-ISSUE #5792] [Bug] inspect-keyed-archive reads an integer payload from the offset table #3511

Closed
opened 2026-10-31 00:41:19 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @morluto on GitHub (Oct 21, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5792

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction

Observed behavior

On compiled revision a00e4ac3630691f90d69a8589090f9ab45f834a4, CLI and SDK-validated stdio MCP accept the malformed generated archive below. Object 1 is reported as kind: "scalar", status: "observed", value: 581275669031437400.

Its integer marker is at byte 100; the offset table begins at 101. The supposed eight-byte integer payload is therefore entirely table bytes, not object data. Those bytes encode 581275669031437385; converting them to a JSON number also rounds them. Apple plutil -lint rejects this same fixture.

Reproduction

Save this as make_fixture.py, then run python3 make_fixture.py ./tmp-plist-boundary:

from pathlib import Path
import sys
# Generated NSKeyedArchive; its integer object deliberately reads table bytes.
data = bytes.fromhex("62706c6973743030d4010203040506070a59246172636869766572582476657273696f6e5424746f7058246f626a656374735f100f4e534b65796564417263686976657212000186a0d1080954726f6f748001a20b0c55246e756c6c333fb999999999991308111b24293244494c515356640000000000000101000000000000000d00000000000000000000000000000065")
out = Path(sys.argv[1]); out.mkdir(parents=True, exist_ok=True)
(out / "numeric-cross-table.plist").write_bytes(data)

Run rea inspect-keyed-archive ./tmp-plist-boundary/numeric-cross-table.plist --json. For MCP, open the file with open_binary({"path":"<absolute fixture path>"}), then call inspect_keyed_archive({}) using its advertised output contract. Both paths reproduced the observed value on the pinned compiled revision. Input SHA-256: 65b691b52420ff1110b90325fd1a4f390b701effced5d2b9c49c514f4c834830; bytes were unchanged after both workflows.

Expected behavior

Refuse the malformed integer record with a typed format failure when its marker or payload crosses the offset-table boundary. Structural bytes must not become observed scalar Evidence. Preserve the input bytes.

Impact and scope

Incorrect observed numeric Evidence from a controlled malformed static archive. Real-world frequency and other untested formats are NOT_ENOUGH_INFO. No target was executed.

REA version

a00e4ac3630691f90d69a8589090f9ab45f834a4 (package 6.7.0).

Runtime and platform

Node.js v24.18.0; macOS 26.3 arm64.

Target and artifact context

Generated binary Foundation keyed archive; integer object 12 begins at offsetTable - 1.

Interface

CLI and MCP

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

{"id":1,"kind":"scalar","status":"observed","value":581275669031437400}

Source-derived cause: keyed archives select decoder bounds (objectsEnd = bytes.length); integer payloads can therefore read beyond the object region. The merged date fix #5786 guards date payloads at offsetTable, but leaves the analogous numeric gap. Apple's binary plist parser bounds object payloads before that table.

This differs from #5783, where a second object aliases bytes inside another valid integer payload. Here the integer's own payload lies in the offset table.

Originally created by @morluto on GitHub (Oct 21, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5792 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Evidence, artifacts, or reconstruction ### Observed behavior On compiled revision `a00e4ac3630691f90d69a8589090f9ab45f834a4`, CLI and SDK-validated stdio MCP accept the malformed generated archive below. Object 1 is reported as `kind: "scalar"`, `status: "observed"`, `value: 581275669031437400`. Its integer marker is at byte 100; the offset table begins at 101. The supposed eight-byte integer payload is therefore entirely table bytes, not object data. Those bytes encode `581275669031437385`; converting them to a JSON number also rounds them. Apple `plutil -lint` rejects this same fixture. ### Reproduction Save this as `make_fixture.py`, then run `python3 make_fixture.py ./tmp-plist-boundary`: ```python from pathlib import Path import sys # Generated NSKeyedArchive; its integer object deliberately reads table bytes. data = bytes.fromhex("62706c6973743030d4010203040506070a59246172636869766572582476657273696f6e5424746f7058246f626a656374735f100f4e534b65796564417263686976657212000186a0d1080954726f6f748001a20b0c55246e756c6c333fb999999999991308111b24293244494c515356640000000000000101000000000000000d00000000000000000000000000000065") out = Path(sys.argv[1]); out.mkdir(parents=True, exist_ok=True) (out / "numeric-cross-table.plist").write_bytes(data) ``` Run `rea inspect-keyed-archive ./tmp-plist-boundary/numeric-cross-table.plist --json`. For MCP, open the file with `open_binary({"path":"<absolute fixture path>"})`, then call `inspect_keyed_archive({})` using its advertised output contract. Both paths reproduced the observed value on the pinned compiled revision. Input SHA-256: `65b691b52420ff1110b90325fd1a4f390b701effced5d2b9c49c514f4c834830`; bytes were unchanged after both workflows. ### Expected behavior Refuse the malformed integer record with a typed format failure when its marker or payload crosses the offset-table boundary. Structural bytes must not become observed scalar Evidence. Preserve the input bytes. ### Impact and scope Incorrect observed numeric Evidence from a controlled malformed static archive. Real-world frequency and other untested formats are `NOT_ENOUGH_INFO`. No target was executed. ### REA version `a00e4ac3630691f90d69a8589090f9ab45f834a4` (package 6.7.0). ### Runtime and platform Node.js v24.18.0; macOS 26.3 arm64. ### Target and artifact context Generated binary Foundation keyed archive; integer object 12 begins at `offsetTable - 1`. ### Interface CLI and MCP ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence ```json {"id":1,"kind":"scalar","status":"observed","value":581275669031437400} ``` Source-derived cause: keyed archives select decoder bounds (`objectsEnd = bytes.length`); integer payloads can therefore read beyond the object region. The merged date fix #5786 guards date payloads at `offsetTable`, but leaves the analogous numeric gap. Apple's [binary plist parser](https://github.com/apple-oss-distributions/CF/blob/main/CFBinaryPList.c) bounds object payloads before that table. This differs from #5783, where a second object aliases bytes inside another valid integer payload. Here the integer's own payload lies in the offset table.
bsakaguchi 2026-10-31 00:41:19 +00:00
  • closed this issue
  • added the
    bug
    triage
    labels
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3511
No description provided.