[GH-ISSUE #6717] [Bug] BEAM inspection rejects nonzero bytes after the declared form #4086

Closed
opened 2026-10-31 00:46:43 +00:00 by bsakaguchi · 0 comments
Owner

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

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

The production BeamService rejects a complete BEAM form when the selected file has the four ordinary ASCII bytes note after its declared end. It returns AnalysisInputError, invalid_format, and BEAM form does not consume the selected file. The identical form with no suffix or four zero bytes succeeds. This happened with both a 28-byte structural fixture and the repository's compiler-produced OTP 29 fixture.

Reproduction

Executed with the checkout's local tsx runner through new BeamService(new BeamProvider()).inspect({ path }). The following is the minimal fixture and the core calls of the executed probe, with imports shown repository-relative; path is an absolute temporary filename:

import { writeFile } from 'node:fs/promises';
import { BeamProvider } from './src/erlang/BeamProvider.ts';
import { BeamService } from './src/application/erlang/BeamService.ts';

const path = '/tmp/rea-beam-trailer.beam';
const form = Buffer.from(
  '464f5231000000144245414d417455380000000600000001016d0000',
  'hex',
);
await writeFile(path, Buffer.concat([form, Buffer.from('note')]));
const service = new BeamService(new BeamProvider());
const result = await service.inspect({ path });
console.log(result);
await service.close();

The form declares one AtU8 chunk containing atom m; all declared ranges and alignment fit. Repeat with form alone or Buffer.concat([form, Buffer.alloc(4)]) for the successful controls. The executed probe also performed all three cases using erlangBeamOtp29Fixture() instead of form. Each of the six cases ran once. No target bytecode or Erlang emulator ran.

Expected behavior

Inspect the declared BEAM form consistently regardless of bytes outside that form, retaining the full selected artifact's identity and the form's own range. OTP's published IFF initializer selects exactly form_size bytes and does not require end-of-file or zero-valued trailing storage. This compatibility expectation is source-derived; loading the suffixed module in Erlang was not tested.

Impact and scope

A bounded compatibility refusal discards all otherwise readable chunk/table facts for BEAM forms followed by nonzero trailer bytes. Both plain and zero-suffixed controls work. Prevalence in real artifacts is unknown. Inspecting a separate copy ending at the declared form boundary provides the demonstrated successful control but changes the artifact digest; the original file need not be modified.

REA version

Unreleased main, exact tested SHA 5d6b8a0ab693c03ab85cf0807d40bedf021e76d8. The manifest says 6.7.0, but this BEAM parser is absent from the fetched published rea-agents-6.7.0 tag. This report does not claim a reproduction in the published package.

Runtime and platform

Node.js v24.22.1; Linux 7.2.8-9-omarchy, x86_64. Built-in TypeScript BEAM reader; no external provider.

Target and artifact context

Synthetic FOR1/BEAM with one atom, plus the unchanged compiler-produced OTP 29 fixture from src/erlang/Beam.fixture.ts, each with no suffix, four zero bytes, or ASCII note after the declared form.

Interface

Other

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Observed service results:

fixture   suffix  artifact bytes  declared form end  result
minimal   none    28              28                 success, module=m
minimal   zero    32              28                 success, module=m
minimal   note    32              28                 invalid_format
compiler  none    564             564                success, module=rea_beam_fixture
compiler  zero    568             564                success, module=rea_beam_fixture
compiler  note    568             564                invalid_format

All successes report complete coverage. Both failures report BEAM form does not consume the selected file. Execution evidence establishes the REA service behavior; expected OTP handling comes from the linked published implementation. Public CLI/MCP adapters and real Erlang loading were not exercised.

Analysis or suspected cause

The parser's trailing-byte guard checks byte values beyond 8 + formSize and rejects the entire inspection when any is nonzero. Those bytes are outside every declared chunk.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: Two harmless forms with readable metadata fail solely because of four nonzero bytes outside the declared form; both corresponding plain and zero-suffixed controls succeed. Real-world frequency is unknown.
  • Workaround status: available
  • Workaround basis: The tested unsuffixed controls contain exactly the affected forms and return their metadata successfully. Inspecting such a separate copy changes its digest and does not preserve the original artifact identity.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6717 ### 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 The production `BeamService` rejects a complete BEAM form when the selected file has the four ordinary ASCII bytes `note` after its declared end. It returns `AnalysisInputError`, `invalid_format`, and `BEAM form does not consume the selected file.` The identical form with no suffix or four zero bytes succeeds. This happened with both a 28-byte structural fixture and the repository's compiler-produced OTP 29 fixture. ### Reproduction Executed with the checkout's local `tsx` runner through `new BeamService(new BeamProvider()).inspect({ path })`. The following is the minimal fixture and the core calls of the executed probe, with imports shown repository-relative; `path` is an absolute temporary filename: ```ts import { writeFile } from 'node:fs/promises'; import { BeamProvider } from './src/erlang/BeamProvider.ts'; import { BeamService } from './src/application/erlang/BeamService.ts'; const path = '/tmp/rea-beam-trailer.beam'; const form = Buffer.from( '464f5231000000144245414d417455380000000600000001016d0000', 'hex', ); await writeFile(path, Buffer.concat([form, Buffer.from('note')])); const service = new BeamService(new BeamProvider()); const result = await service.inspect({ path }); console.log(result); await service.close(); ``` The form declares one `AtU8` chunk containing atom `m`; all declared ranges and alignment fit. Repeat with `form` alone or `Buffer.concat([form, Buffer.alloc(4)])` for the successful controls. The executed probe also performed all three cases using `erlangBeamOtp29Fixture()` instead of `form`. Each of the six cases ran once. No target bytecode or Erlang emulator ran. ### Expected behavior Inspect the declared BEAM form consistently regardless of bytes outside that form, retaining the full selected artifact's identity and the form's own range. OTP's published [IFF initializer](https://github.com/erlang/otp/blob/550d7b7898706c7822362c42e7b93120c1d1f29a/erts/emulator/beam/beam_file.c#L1897-L1913) selects exactly `form_size` bytes and does not require end-of-file or zero-valued trailing storage. This compatibility expectation is source-derived; loading the suffixed module in Erlang was not tested. ### Impact and scope A bounded compatibility refusal discards all otherwise readable chunk/table facts for BEAM forms followed by nonzero trailer bytes. Both plain and zero-suffixed controls work. Prevalence in real artifacts is unknown. Inspecting a separate copy ending at the declared form boundary provides the demonstrated successful control but changes the artifact digest; the original file need not be modified. ### REA version Unreleased `main`, exact tested SHA `5d6b8a0ab693c03ab85cf0807d40bedf021e76d8`. The manifest says `6.7.0`, but this BEAM parser is absent from the fetched published `rea-agents-6.7.0` tag. This report does not claim a reproduction in the published package. ### Runtime and platform Node.js `v24.22.1`; Linux `7.2.8-9-omarchy`, x86_64. Built-in TypeScript BEAM reader; no external provider. ### Target and artifact context Synthetic FOR1/BEAM with one atom, plus the unchanged compiler-produced OTP 29 fixture from `src/erlang/Beam.fixture.ts`, each with no suffix, four zero bytes, or ASCII `note` after the declared form. ### Interface Other ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence Observed service results: ```text fixture suffix artifact bytes declared form end result minimal none 28 28 success, module=m minimal zero 32 28 success, module=m minimal note 32 28 invalid_format compiler none 564 564 success, module=rea_beam_fixture compiler zero 568 564 success, module=rea_beam_fixture compiler note 568 564 invalid_format ``` All successes report complete coverage. Both failures report `BEAM form does not consume the selected file.` Execution evidence establishes the REA service behavior; expected OTP handling comes from the linked published implementation. Public CLI/MCP adapters and real Erlang loading were not exercised. ### Analysis or suspected cause [The parser's trailing-byte guard](https://github.com/morluto/rea/blob/5d6b8a0ab693c03ab85cf0807d40bedf021e76d8/src/erlang/BeamParser.ts#L225-L230) checks byte values beyond `8 + formSize` and rejects the entire inspection when any is nonzero. Those bytes are outside every declared chunk. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: Two harmless forms with readable metadata fail solely because of four nonzero bytes outside the declared form; both corresponding plain and zero-suffixed controls succeed. Real-world frequency is unknown. - Workaround status: available - Workaround basis: The tested unsuffixed controls contain exactly the affected forms and return their metadata successfully. Inspecting such a separate copy changes its digest and does not preserve the original artifact identity.
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#4086
No description provided.