[GH-ISSUE #8453] [Bug] File validation diagnostics can overflow the MCP response #6612

Open
opened 2026-11-01 21:12:40 +00:00 by bsakaguchi · 5 comments
Owner

Originally created by @morluto on GitHub (Nov 1, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8453

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; MCP file-backed input diagnostics.

Observed behavior

On main e18594b24754ab95ebd119311cc32a1d1ad6fa13, a malformed standalone Evidence file with many invalid fields caused inspect_analysis_view to return a transport resource_constraint instead of the original file invalid_request and selected path. The response named original_error_code: "invalid_request" and provided a retained reference to the complete original error; it did not lose that error. The returned transport diagnostic did not directly include the selected file path.

Reproduction

  1. Construct JSON from FUNCTION_COMPARISON_EXAMPLE.left, replacing limitations with 125,000 numeric values (invalid because each limitation must be a string), and write it to an owned local file. The resulting file was 376,625 bytes.
  2. On the tested main revision, start the production MCP server with REA_MCP_MAX_RESPONSE_BYTES unset, using the TypeScript SDK in-memory transport, full schema profile, and no provider.
  3. Call inspect_analysis_view with source: {kind: "evidence-file", path: <absolute path>} and view: {kind: "summary"}.
  4. The call returned resource_constraint at the MCP response boundary, with original_error_code: "invalid_request", result_budget_bytes: 10484736, response_bytes_at_least: 10498324, and an Evidence reference for the retained original error. The response did not include details.path. A 20,000-value control returned the direct invalid_request with the selected path in both full and compact profiles; its call result serialized to 1,729,549 bytes.

Expected behavior

Keep the original typed file error and selected path directly visible when field-level issue details cannot fit, with explicit omission or bounded paging. Preserve complete diagnostics where available and do not silently treat an incomplete list as complete. Bound representation expansion before allocation; do not impose a new arbitrary limit on valid Evidence files.

Impact and scope

Observed with a deliberately malformed synthetic file, no provider or target interaction. The 125,000-value reproduction used the default MCP response setting and full profile; the smaller control exercised both profiles. No claim about frequency, OOM, production data, or other clients/platforms. The original error was retained and a subsequent get_evidence_bundle summary succeeded; recoverability after session loss was not tested.

REA version

Source revision e18594b24754ab95ebd119311cc32a1d1ad6fa13.

Runtime and platform

Node 24.22.1, macOS arm64, public MCP registration and TypeScript SDK in-memory transport.

Target and artifact context

Synthetic malformed Evidence JSON derived from the public function-comparison fixture; no target execution or provider started.

Interface

MCP.

Earliest failure stage

Evidence-file validation and error delivery.

Relevant output or evidence

  • 20,000 invalid values: direct invalid_request, file path and 20,000 field issues.
  • 125,000 invalid values: transport resource_constraint, original-error reference and no direct file path.
  • Source-derived: the standalone reader eagerly projects all Zod issues before the MCP response budget is applied; the projected error can expand far beyond the selected file. The SDK's input-element guard does not inspect file contents. #7882 addressed SDK argument validation rather than this file-reader boundary.

Typed outcome or recovery expected

An actionable file validation error with the original path and bounded, explicitly incomplete field diagnostics; the original full diagnostics remain accessible only where an owned bounded mechanism supports them.

Analysis or suspected cause

readEvidenceFileSource projects the entire validator issue list and the generic error delivery later enforces the response budget. A prototype in #8427 defers issue projection until the MCP budget is known and passes a smaller injected-budget control, but validation itself still produces the issue list; validator-time allocation and nested failure aggregation remain unverified. This is not a claim that the prototype resolves the whole resource boundary.

Additional context

Related: #7882, #8427, #8449. No upstream Ghidra or Kuna issue is implied.

cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0

Originally created by @morluto on GitHub (Nov 1, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8453 ### 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; MCP file-backed input diagnostics. ### Observed behavior On main `e18594b24754ab95ebd119311cc32a1d1ad6fa13`, a malformed standalone Evidence file with many invalid fields caused `inspect_analysis_view` to return a transport `resource_constraint` instead of the original file `invalid_request` and selected path. The response named `original_error_code: "invalid_request"` and provided a retained reference to the complete original error; it did not lose that error. The returned transport diagnostic did not directly include the selected file path. ### Reproduction 1. Construct JSON from `FUNCTION_COMPARISON_EXAMPLE.left`, replacing `limitations` with 125,000 numeric values (invalid because each limitation must be a string), and write it to an owned local file. The resulting file was 376,625 bytes. 2. On the tested main revision, start the production MCP server with `REA_MCP_MAX_RESPONSE_BYTES` unset, using the TypeScript SDK in-memory transport, full schema profile, and no provider. 3. Call `inspect_analysis_view` with `source: {kind: "evidence-file", path: <absolute path>}` and `view: {kind: "summary"}`. 4. The call returned `resource_constraint` at the MCP response boundary, with `original_error_code: "invalid_request"`, `result_budget_bytes: 10484736`, `response_bytes_at_least: 10498324`, and an Evidence reference for the retained original error. The response did not include `details.path`. A 20,000-value control returned the direct `invalid_request` with the selected path in both full and compact profiles; its call result serialized to 1,729,549 bytes. ### Expected behavior Keep the original typed file error and selected path directly visible when field-level issue details cannot fit, with explicit omission or bounded paging. Preserve complete diagnostics where available and do not silently treat an incomplete list as complete. Bound representation expansion before allocation; do not impose a new arbitrary limit on valid Evidence files. ### Impact and scope Observed with a deliberately malformed synthetic file, no provider or target interaction. The 125,000-value reproduction used the default MCP response setting and full profile; the smaller control exercised both profiles. No claim about frequency, OOM, production data, or other clients/platforms. The original error was retained and a subsequent `get_evidence_bundle` summary succeeded; recoverability after session loss was not tested. ### REA version Source revision `e18594b24754ab95ebd119311cc32a1d1ad6fa13`. ### Runtime and platform Node 24.22.1, macOS arm64, public MCP registration and TypeScript SDK in-memory transport. ### Target and artifact context Synthetic malformed Evidence JSON derived from the public function-comparison fixture; no target execution or provider started. ### Interface MCP. ### Earliest failure stage Evidence-file validation and error delivery. ### Relevant output or evidence - 20,000 invalid values: direct `invalid_request`, file path and 20,000 field issues. - 125,000 invalid values: transport `resource_constraint`, original-error reference and no direct file path. - Source-derived: the standalone reader eagerly projects all Zod issues before the MCP response budget is applied; the projected error can expand far beyond the selected file. The SDK's input-element guard does not inspect file contents. #7882 addressed SDK argument validation rather than this file-reader boundary. ### Typed outcome or recovery expected An actionable file validation error with the original path and bounded, explicitly incomplete field diagnostics; the original full diagnostics remain accessible only where an owned bounded mechanism supports them. ### Analysis or suspected cause `readEvidenceFileSource` projects the entire validator issue list and the generic error delivery later enforces the response budget. A prototype in #8427 defers issue projection until the MCP budget is known and passes a smaller injected-budget control, but validation itself still produces the issue list; validator-time allocation and nested failure aggregation remain unverified. This is not a claim that the prototype resolves the whole resource boundary. ### Additional context Related: #7882, #8427, #8449. No upstream Ghidra or Kuna issue is implied. cc @gensokyo-dev @kaoru0822-kitauji @N0zoM1z0
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

An isolated, unmerged prototype was exercised on the same 125,000-value file with REA_MCP_MAX_RESPONSE_BYTES unset and the full schema profile. Its shared file reader returned an 831-byte evidence_integrity_mismatch response with the selected path and content_issues_omitted: true; no record was retained, and a following bundle-summary call succeeded. The prototype classifies a recognized malformed Evidence record as an integrity error, so its code differs from main's original invalid_request. This is a candidate contract change, not evidence that the behavior is fixed on main.

The prototype postpones issue projection until the MCP response allowance is known and explicitly reports omission. It does not bound Zod's generation of the 125,000 issues. Nested failures, large first-issue messages, memory pressure, other transports, and actual-agent recovery remain unverified. A final design should address the producing validation boundary and preserve useful small-error diagnostics without silently dropping facts.

Stdio follow-up: The same file was tested through separate production stdio MCP server processes with REA_MCP_MAX_RESPONSE_BYTES unset and both full and compact output profiles. On main, both returned the transport constraint with a retained original-error reference and without the selected path; a subsequent bundle-summary call succeeded. The unmerged prototype returned evidence_integrity_mismatch with the selected path and content_issues_omitted: true in both profiles; its follow-up summary also succeeded. The prototype's issue-generation and broader validation limits above still apply. Neither run started a provider or executed a target.

A further synthetic control used an otherwise valid-shaped record with one 65,544-character unknown top-level key and an injected 32 KiB response budget. Deferring field-issue projection alone still produced a transport error because Zod's first-issue message included the whole key. In the prototype, the shared validation-summary owner now reports the count of unrecognized keys; exact key details remain in the structured issues when they fit, or are explicitly marked omitted. The control then returned the file-integrity error and selected path in both schema profiles. This is an injected-budget result, not a default-limit reproduction for the single long key; other oversized paths and issue types remain unverified. Four focused CLI/MCP/projection/redaction suites passed 127 tests, and typecheck/lint passed.

<!-- gh-comment-id:6555096606 --> @morluto commented on GitHub (Nov 1, 2026): An isolated, unmerged prototype was exercised on the same 125,000-value file with `REA_MCP_MAX_RESPONSE_BYTES` unset and the full schema profile. Its shared file reader returned an 831-byte `evidence_integrity_mismatch` response with the selected path and `content_issues_omitted: true`; no record was retained, and a following bundle-summary call succeeded. The prototype classifies a recognized malformed Evidence record as an integrity error, so its code differs from main's original `invalid_request`. This is a candidate contract change, not evidence that the behavior is fixed on main. The prototype postpones **issue projection** until the MCP response allowance is known and explicitly reports omission. It does not bound Zod's generation of the 125,000 issues. Nested failures, large first-issue messages, memory pressure, other transports, and actual-agent recovery remain unverified. A final design should address the producing validation boundary and preserve useful small-error diagnostics without silently dropping facts. **Stdio follow-up:** The same file was tested through separate production stdio MCP server processes with `REA_MCP_MAX_RESPONSE_BYTES` unset and both full and compact output profiles. On main, both returned the transport constraint with a retained original-error reference and without the selected path; a subsequent bundle-summary call succeeded. The unmerged prototype returned `evidence_integrity_mismatch` with the selected path and `content_issues_omitted: true` in both profiles; its follow-up summary also succeeded. The prototype's issue-generation and broader validation limits above still apply. Neither run started a provider or executed a target. A further synthetic control used an otherwise valid-shaped record with one 65,544-character unknown top-level key and an injected 32 KiB response budget. Deferring field-issue projection alone still produced a transport error because Zod's first-issue message included the whole key. In the prototype, the shared validation-summary owner now reports the count of unrecognized keys; exact key details remain in the structured issues when they fit, or are explicitly marked omitted. The control then returned the file-integrity error and selected path in both schema profiles. This is an injected-budget result, not a default-limit reproduction for the single long key; other oversized paths and issue types remain unverified. Four focused CLI/MCP/projection/redaction suites passed 127 tests, and typecheck/lint passed.
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

Validator investigation: The installed Zod is 4.6.6. Its public schema.validate() reports a boolean and can stop early; it does not provide parsed output or a field-level error. In a controlled schema with 125,000 values and the first invalid, an instrumented element refinement ran once for validate() and 125,000 times for safeParse(). This is a visit-count control, not a performance benchmark or a guarantee for every schema.

With previously captured real Ghidra and Kuna function records, evidenceSchema.validate() and REA's authenticated parser both accepted the originals. For each, changing a function name without updating its Evidence ID was still accepted by the shape validator but rejected by the authenticated parser. A mismatched profile/provider was rejected by the shape validator. Thus validate() cannot replace identity authentication, and its boolean alone would lose useful field paths. The installed source also shows that validation may run transforms; REA's JSON value schema performs a value-preserving transform, so a preflight is not necessarily allocation-free or free on valid records.

A possible direction is to retain the authenticated parser for accepted records while investigating a bounded diagnostic strategy for malformed data. That requires testing valid large records, normal field diagnostics, malformed nested records, digest failures, and actual memory/elapsed costs; no such production change is proposed by this control. Captured inputs were previously produced by real providers but this check started neither provider.

A second controlled Zod 4.6.6 probe instrumented array pushes while validating a strict object with 20,000 unexpected keys. validate() rejected it, but the runtime pushed all 20,000 keys into its unknown-key list before returning. This matches the installed handleCatchall source. Consequently, early termination on the array example is not a general constant-memory guarantee; this was a synthetic instrumented call, not a measurement of a real REA request.

<!-- gh-comment-id:6555124824 --> @morluto commented on GitHub (Nov 1, 2026): **Validator investigation:** The installed Zod is 4.6.6. Its public [`schema.validate()`](https://github.com/colinhacks/zod/blob/v4.6.6/packages/docs/content/basics.mdx) reports a boolean and can stop early; it does not provide parsed output or a field-level error. In a controlled schema with 125,000 values and the first invalid, an instrumented element refinement ran once for `validate()` and 125,000 times for `safeParse()`. This is a visit-count control, not a performance benchmark or a guarantee for every schema. With previously captured real Ghidra and Kuna function records, `evidenceSchema.validate()` and REA's authenticated parser both accepted the originals. For each, changing a function name without updating its Evidence ID was still accepted by the shape validator but rejected by the authenticated parser. A mismatched profile/provider was rejected by the shape validator. Thus `validate()` cannot replace identity authentication, and its boolean alone would lose useful field paths. The installed source also shows that validation may run transforms; REA's JSON value schema performs a value-preserving transform, so a preflight is not necessarily allocation-free or free on valid records. A possible direction is to retain the authenticated parser for accepted records while investigating a bounded diagnostic strategy for malformed data. That requires testing valid large records, normal field diagnostics, malformed nested records, digest failures, and actual memory/elapsed costs; no such production change is proposed by this control. Captured inputs were previously produced by real providers but this check started neither provider. A second controlled Zod 4.6.6 probe instrumented array pushes while validating a strict object with 20,000 unexpected keys. `validate()` rejected it, but the runtime pushed all 20,000 keys into its unknown-key list before returning. This matches the installed `handleCatchall` source. Consequently, early termination on the array example is not a general constant-memory guarantee; this was a synthetic instrumented call, not a measurement of a real REA request.
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

Constrained-heap process failure before diagnostic projection

A further controlled check shows that bounding the projected response does not bound validation itself. On macOS arm64 / Node 24.22.1, I started fresh public stdio servers with --max-old-space-size=128 and compact schemas. A 381,310-byte synthetic record, based on a captured Kuna dossier but with 125,000 numeric values where limitation strings belong, caused both main revision e18594b and the unmerged raw-import prototype to terminate during import_evidence_bundle; the SDK received Connection closed and each server's stderr reported heap exhaustion. No provider or target ran. Under the same cap, the prototype imported the original 6,908-byte valid record and answered a subsequent summary; main correctly refused that standalone record as invalid input and also answered a summary. The old-space cap is an injected test setting, not a measurement of default-heap failure frequency.

To locate the stage, a separate instrumented process constructed the prototype's production server components and called the shared file reader directly. For the 125,000-value case it completed JSON reading and passed requireAuthenticationHeadroom, then aborted inside safeParseImmutableEvidence before that call returned or MCP error projection began. A 20,000-value control returned 20,000 validation issues and completed projection. In contrast, a standalone validator process without the server components returned all 125,000 issues under the same old-space flag, showing that the failure depends on actual live heap state; the count is not a universal threshold.

In that server-loaded control, evidenceSchema.validate returned false for the 125,000 invalid values without exhausting the heap. It returned true for a shape-valid record whose result had been changed without updating its Evidence ID; the subsequent authenticated parse correctly rejected it. Therefore the boolean check is not a replacement for semantic authentication, and its public API supplies no detailed issues. Previous controlled instrumentation also showed that .validate() can collect all unknown keys, so this single example does not establish a general memory bound. A fix needs the validation owner to bound issue production or otherwise admit its worst relevant working representation before allocation, while preserving useful diagnostics and exact authentication; merely truncating the eventual MCP reply is insufficient.

Related raw-record recovery design: #8427. No claim about other operating systems, provider failure rates, or the released default heap.

Main later advanced to a6caa79bf with a CI-only commit; that newer revision was not runtime-tested in this control.

<!-- gh-comment-id:6555620875 --> @morluto commented on GitHub (Nov 1, 2026): ### Constrained-heap process failure before diagnostic projection A further controlled check shows that bounding the **projected response** does not bound validation itself. On macOS arm64 / Node 24.22.1, I started fresh public stdio servers with `--max-old-space-size=128` and compact schemas. A 381,310-byte synthetic record, based on a captured Kuna dossier but with 125,000 numeric values where limitation strings belong, caused both main revision `e18594b` and the unmerged raw-import prototype to terminate during `import_evidence_bundle`; the SDK received `Connection closed` and each server's stderr reported heap exhaustion. No provider or target ran. Under the same cap, the prototype imported the original 6,908-byte valid record and answered a subsequent summary; main correctly refused that standalone record as invalid input and also answered a summary. The old-space cap is an injected test setting, not a measurement of default-heap failure frequency. To locate the stage, a separate instrumented process constructed the prototype's production server components and called the shared file reader directly. For the 125,000-value case it completed JSON reading and passed `requireAuthenticationHeadroom`, then aborted inside `safeParseImmutableEvidence` before that call returned or MCP error projection began. A 20,000-value control returned 20,000 validation issues and completed projection. In contrast, a standalone validator process without the server components returned all 125,000 issues under the same old-space flag, showing that the failure depends on actual live heap state; the count is not a universal threshold. In that server-loaded control, `evidenceSchema.validate` returned `false` for the 125,000 invalid values without exhausting the heap. It returned `true` for a shape-valid record whose result had been changed without updating its Evidence ID; the subsequent authenticated parse correctly rejected it. Therefore the boolean check is not a replacement for semantic authentication, and its public API supplies no detailed issues. Previous controlled instrumentation also showed that `.validate()` can collect all unknown keys, so this single example does not establish a general memory bound. A fix needs the validation owner to bound issue production or otherwise admit its worst relevant working representation before allocation, while preserving useful diagnostics and exact authentication; merely truncating the eventual MCP reply is insufficient. Related raw-record recovery design: #8427. No claim about other operating systems, provider failure rates, or the released default heap. Main later advanced to `a6caa79bf` with a CI-only commit; that newer revision was not runtime-tested in this control.
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

Additional reproduction on the existing public import path, tested on e18594b24754ab95ebd119311cc32a1d1ad6fa13, macOS arm64, compact MCP schema profile. Version correction: the original runs in this comment used Node 26.5.0, not 24.22.1 as first stated. I reran the public bundle-import control with the pinned Node 24.22.1: the valid bundle imported and the same malformed bundle again closed the connection with V8 heap exhaustion. The isolated Ajv results and 240/1,680-case differential below were originally run on Node 26.5.0. The server was deliberately launched with --max-old-space-size=128 for this resource-pressure test; this is not REA's default.

  • A 7,187-byte canonical bundle containing a real Kuna Evidence record imported successfully through the TypeScript SDK's stdio MCP transport, and a subsequent bundle summary succeeded.
  • Changing only that record's limitations to 125,000 numeric entries produced a 381,589-byte malformed bundle. import_evidence_bundle ended with SDK Connection closed; the server's stderr reported V8 heap exhaustion. No provider or target was needed during import. This reproduces the allocation problem in the existing bundle path, independently of the experimental raw-record import in #8427.

I also tested a possible direction in an isolated harness, not a product change. A JSON Schema generated from the owning Zod Evidence/bundle schema, compiled with Ajv allErrors: false, returned a first invalid location for the 125,000 invalid limitations and for a separate invalid unknowns array under the same heap setting. It accepted the valid real Kuna bundle; a content-tampered bundle passed the structural precheck but failed the existing full authentication, as required. Real Ghidra and Kuna individual records also passed both stages. A separate finite differential sample of 240 generated valid records and 1,680 invalid variations found no Zod/Ajv shape disagreement.

This is evidence for further investigation, not proof that the precheck is safe or a fix. The harness instantiated production server components but did not send its precheck through MCP. Schema conversion can omit Zod refinements (including semantic identity), and a finite sample cannot prove it will never reject a valid input. Authentication and bundle invariants remain mandatory; generated-schema compatibility, all affected file entry points, useful explicitly incomplete diagnostics, and validation allocation for other input shapes still need verification before integration. The valid/malformed public MCP reproduction above did not use this experimental precheck.

<!-- gh-comment-id:6555690201 --> @morluto commented on GitHub (Nov 1, 2026): Additional reproduction on the existing public import path, tested on `e18594b24754ab95ebd119311cc32a1d1ad6fa13`, macOS arm64, compact MCP schema profile. **Version correction:** the original runs in this comment used Node 26.5.0, not 24.22.1 as first stated. I reran the public bundle-import control with the pinned Node 24.22.1: the valid bundle imported and the same malformed bundle again closed the connection with V8 heap exhaustion. The isolated Ajv results and 240/1,680-case differential below were originally run on Node 26.5.0. The server was deliberately launched with `--max-old-space-size=128` for this resource-pressure test; this is not REA's default. - A 7,187-byte canonical bundle containing a real Kuna Evidence record imported successfully through the TypeScript SDK's stdio MCP transport, and a subsequent bundle summary succeeded. - Changing only that record's `limitations` to 125,000 numeric entries produced a 381,589-byte malformed bundle. `import_evidence_bundle` ended with SDK `Connection closed`; the server's stderr reported V8 heap exhaustion. No provider or target was needed during import. This reproduces the allocation problem in the existing bundle path, independently of the experimental raw-record import in #8427. I also tested a possible direction in an isolated harness, not a product change. A JSON Schema generated from the owning Zod Evidence/bundle schema, compiled with Ajv `allErrors: false`, returned a first invalid location for the 125,000 invalid limitations and for a separate invalid unknowns array under the same heap setting. It accepted the valid real Kuna bundle; a content-tampered bundle passed the structural precheck but failed the existing full authentication, as required. Real Ghidra and Kuna individual records also passed both stages. A separate finite differential sample of 240 generated valid records and 1,680 invalid variations found no Zod/Ajv shape disagreement. This is evidence for further investigation, **not proof that the precheck is safe or a fix**. The harness instantiated production server components but did not send its precheck through MCP. Schema conversion can omit Zod refinements (including semantic identity), and a finite sample cannot prove it will never reject a valid input. Authentication and bundle invariants remain mandatory; generated-schema compatibility, all affected file entry points, useful explicitly incomplete diagnostics, and validation allocation for other input shapes still need verification before integration. The valid/malformed public MCP reproduction above did not use this experimental precheck.
Author
Owner

@morluto commented on GitHub (Nov 1, 2026):

Correction to the precheck experiment above: the generated-JSON-Schema/Ajv precheck does not solve validator-time amplification as tested.

residualUnknownSchema uses z.string().trim().min(1) for a recommended probe's rationale. Zod rejects a whitespace-only string after trimming, but its generated input JSON Schema is just {"type":"string","minLength":1} and Ajv accepts " ". In the original Node 26.5.0 isolated production-server-component harness under the same test-only --max-old-space-size=128, a bundle with 75,000 recommended probes whose rationales were " " passed the existing headroom check and the Ajv precheck, then aborted with V8 heap exhaustion during the subsequent Zod bundle authentication. A one-probe control likewise passed Ajv and failed full authentication; a 20,000-probe case failed authentication without crashing. The 75,000-probe JSON file was 3,007,802 bytes. No target or provider was run, and this particular counterexample used the isolated harness rather than a public MCP call.

This confirms that merely putting a validator generated from the input JSON Schema in front of Zod leaves a real route to the same amplification. Any eventual solution must account for omitted transformations and refinements, as well as preserve full authentication and bounded useful diagnostics. The earlier results remain useful controls for specific structural errors, not evidence for adopting that precheck as a general fix.

Follow-up public control: the same malformed 3,007,802-byte bundle also caused SDK Connection closed with V8 heap exhaustion through the existing import_evidence_bundle stdio MCP tool on the tested main revision with the same test-only old-space setting. This happened both in the original Node 26.5.0 run and on a separate rerun with the pinned Node 24.22.1. The public server had no Ajv precheck; the isolated test above establishes that adding that precheck alone would let this input reach authentication.

Pinned Node 24.22.1 isolated rerun: the one-probe input passed Ajv and failed authentication; the 75,000-probe input passed headroom and Ajv, then aborted during authentication. The 20,000-probe case aborted after the headroom marker and before the Ajv return marker, so the earlier 20,000-probe non-crash observation applies only to the original Node 26.5.0 run. Heap and live-server state affect where these artificial constrained tests fail.

<!-- gh-comment-id:6555699847 --> @morluto commented on GitHub (Nov 1, 2026): Correction to the precheck experiment above: **the generated-JSON-Schema/Ajv precheck does not solve validator-time amplification as tested.** `residualUnknownSchema` uses `z.string().trim().min(1)` for a recommended probe's `rationale`. Zod rejects a whitespace-only string after trimming, but its generated input JSON Schema is just `{"type":"string","minLength":1}` and Ajv accepts `" "`. In the original Node 26.5.0 isolated production-server-component harness under the same test-only `--max-old-space-size=128`, a bundle with 75,000 recommended probes whose rationales were `" "` passed the existing headroom check **and the Ajv precheck**, then aborted with V8 heap exhaustion during the subsequent Zod bundle authentication. A one-probe control likewise passed Ajv and failed full authentication; a 20,000-probe case failed authentication without crashing. The 75,000-probe JSON file was 3,007,802 bytes. No target or provider was run, and this particular counterexample used the isolated harness rather than a public MCP call. This confirms that merely putting a validator generated from the input JSON Schema in front of Zod leaves a real route to the same amplification. Any eventual solution must account for omitted transformations and refinements, as well as preserve full authentication and bounded useful diagnostics. The earlier results remain useful controls for specific structural errors, not evidence for adopting that precheck as a general fix. Follow-up public control: the same malformed 3,007,802-byte bundle also caused SDK `Connection closed` with V8 heap exhaustion through the existing `import_evidence_bundle` stdio MCP tool on the tested main revision with the same test-only old-space setting. This happened both in the original Node 26.5.0 run and on a separate rerun with the pinned Node 24.22.1. The public server had no Ajv precheck; the isolated test above establishes that adding that precheck alone would let this input reach authentication. **Pinned Node 24.22.1 isolated rerun:** the one-probe input passed Ajv and failed authentication; the 75,000-probe input passed headroom and Ajv, then aborted during authentication. The 20,000-probe case aborted after the headroom marker and before the Ajv return marker, so the earlier 20,000-probe non-crash observation applies only to the original Node 26.5.0 run. Heap and live-server state affect where these artificial constrained tests fail.
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#6612
No description provided.