[GH-ISSUE #7531] [Bug] PE certificate decoder budgets are reported as malformed input #4474

Closed
opened 2026-10-31 00:50:08 +00:00 by bsakaguchi · 0 comments
Owner

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

Before submitting

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

Area

Native analysis or decompilation

Observed behavior

node scripts/rea.mjs inspect-pe-certificates "$WORK/certs-400.exe" --json refuses a synthetic certificate table with code: "invalid_request", category: "invalid_input", and a path issue with reason invalid_format, although its diagnostic identifies exhaustion of the fixed decoded-text budget. Recovery tells the caller to inspect the input schema and correct request fields. The same happens for the ASN.1 node budget with certs-600.exe.

The refusal itself is expected at the fixed allowance. The incorrect behavior is treating the exhausted decoder allowance as malformed PKCS#7 and request-field invalidity. Both failures already correctly report retryable: false. Smaller fixtures generated by the same procedure return complete certificate inventories.

Reproduction

  1. Use the source revision below with its prepared build, locked dependencies, and Node.js v24.22.1. From the checkout root, run this complete fixture generator and public CLI replay. It uses Python-free, inert, definite-length CMS structures; no target binary executes. For a clean environment, unset any pre-existing REA_*, HOPPER_*, GHIDRA_*, and NODE_OPTIONS overrides before running.
WORK="$(mktemp -d)"
export WORK
export HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config" \
  XDG_DATA_HOME="$WORK/data" XDG_CACHE_HOME="$WORK/cache" \
  XDG_STATE_HOME="$WORK/state" XDG_RUNTIME_DIR="$WORK/runtime"
mkdir -p "$HOME" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" \
  "$XDG_CACHE_HOME" "$XDG_STATE_HOME" "$XDG_RUNTIME_DIR"
cat > "$WORK/make.mjs" <<'JS'
import { writeFileSync } from 'node:fs';
import { join } from 'node:path';
const out = process.argv[2];
function value(tag, ...parts) {
  const body = Buffer.concat(parts.map(p => typeof p === 'string' ? Buffer.from(p) : p));
  let n = body.length;
  const octets = [];
  do { octets.unshift(n & 255); n = Math.floor(n / 256); } while (n);
  const size = body.length < 128 ? [body.length] : [128 + octets.length, ...octets];
  return Buffer.concat([Buffer.from([tag, ...size]), body]);
}
const sequence = (...v) => value(0x30, ...v);
const set = (...v) => value(0x31, ...v);
const int = n => {
  const bytes = []; do { bytes.unshift(n & 255); n = Math.floor(n / 256); } while (n);
  if (bytes[0] >= 128) bytes.unshift(0);
  return value(2, Buffer.from(bytes));
};
const oid = hex => value(6, Buffer.from(hex, 'hex'));
const algorithm = hex => sequence(oid(hex), value(5));
const sha256 = algorithm('608648016503040201');
const rsaSha256 = algorithm('2a864886f70d01010b');
const name = i => sequence(set(sequence(oid('550403'), value(12, `Verifier ${i}`))));
const bitString = s => value(3, Buffer.from([0]), s);
function certificate(i) {
  return sequence(sequence(
    value(0xa0, int(2)), int(i + 1), rsaSha256, name(i),
    sequence(value(23, '250101000000Z'), value(23, '260101000000Z')),
    name(i), sequence(algorithm('2a864886f70d010101'), bitString('key'))
  ), rsaSha256, bitString('signature'));
}
function cms(count) {
  const signer = sequence(int(1), sequence(name(0), int(1)),
    sha256, rsaSha256, value(4, 'signature'));
  const certificates = Array.from({length: count}, (_, i) => certificate(i));
  return sequence(oid('2a864886f70d010702'), value(0xa0, sequence(
    int(1), set(sha256), sequence(oid('2a864886f70d010701')),
    value(0xa0, ...certificates), set(signer))));
}
function image(payload) {
  const length = payload.length + 8;
  const table = Buffer.alloc(Math.ceil(length / 8) * 8);
  table.writeUInt32LE(length, 0); table.writeUInt16LE(0x200, 4); table.writeUInt16LE(2, 6);
  payload.copy(table, 8);
  const headers = Buffer.alloc(512);
  headers.write('MZ'); headers.writeUInt32LE(128, 60); headers.write('PE\0\0', 128);
  headers.writeUInt16LE(0x14c, 132); headers.writeUInt16LE(1, 134);
  headers.writeUInt16LE(224, 148); headers.writeUInt16LE(0x10b, 152);
  headers.writeUInt32LE(512, 212); headers.writeUInt32LE(16, 244);
  headers.writeUInt32LE(512, 280); headers.writeUInt32LE(table.length, 284);
  return Buffer.concat([headers, table]);
}
for (const count of [2, 200, 400, 600]) {
  const payload = cms(count);
  writeFileSync(join(out, `certs-${count}.exe`), image(payload));
  writeFileSync(join(out, `certs-${count}.p7b`), payload);
  console.log(JSON.stringify({count, payloadBytes: payload.length, fileBytes: image(payload).length}));
}
JS
node "$WORK/make.mjs" "$WORK"
for count in 2 200 400 600; do
  for attempt in 1 2; do
    node scripts/rea.mjs inspect-pe-certificates "$WORK/certs-$count.exe" --json \
      > "$WORK/result-$count-$attempt.json" 2> "$WORK/stderr-$count-$attempt.txt"
    printf 'certificates=%s attempt=%s exit=%s\n' "$count" "$attempt" "$?"
  done
done
node --input-type=module <<'JS'
import {readFileSync} from 'node:fs';
for (const count of [2,200,400,600]) {
  const result = JSON.parse(readFileSync(`${process.env.WORK}/result-${count}-1.json`));
  console.log(JSON.stringify({count, coverage: result.normalized_result?.coverage,
    code: result.code, category: result.category, retryable: result.retryable,
    recovery: result.recovery, issues: result.details?.issues}));
}
JS
  1. Observe exit 0 and complete coverage with 2 and 200 certificates. Both 400-certificate calls exit 1 with the decoded-text-budget diagnostic; both 600-certificate calls exit 1 with the node-budget diagnostic. Each failure has the invalid-input classification and input-contract recovery shown below. All eight calls had empty stderr.

This exact inline procedure was replayed once during verification, with two calls per input. The same final fixtures had also produced these results in an earlier independent CLI replay.

Expected behavior

Keep the bounded refusal and the existing no-partial-success behavior. Report an exhausted fixed decoder allowance as a non-retryable resource_constraint, naming the applicable allowance and numeric limit, with recovery explaining that the allowance is fixed. A request-field correction cannot raise it.

The documented operation performs bounded structural inspection and explicitly gives decoded certificate fields a shared 64 KiB budget. The shared semantic error contract distinguishes bounded resource admission refusals from malformed input and provides recovery for fixed decoder allowances. This expectation does not require accepting larger payloads, raising the limits, validating signatures, or returning partial inventories.

Impact and scope

P2: callers receive the wrong machine-readable failure category and recovery discriminator for two deterministic decoder-capacity refusals. The observed error identifies the selected path as invalid format instead of preserving resource exhaustion. No downstream automated retry loop or incorrect successful analysis was observed.

The tested scope is four synthetic PE32 files with one type-2 WIN_CERTIFICATE each. The 400-certificate file is 65016 bytes and the 600-certificate file is 97416 bytes, both far below the default 64 MiB file-read budget and using only one of the default eight table entries. The complete inventory is unavailable on refusal, as intended by the bounded operation; the report concerns classification and recovery rather than that intentional lack of partial output.

NOT_ENOUGH_INFO: prevalence in real signed binaries, a same-artifact public workaround, and downstream caller consequences were not established. The strict request schema exposes file-byte and table-entry limits, with no override for these decoder allowances. Signature validity and Windows trust acceptance were not tested or asserted.

REA version

Exact node scripts/rea.mjs --version output:

6.8.0

Source commit: 65f1c447344a423fa2785847dbcea1e9a9e2454a.

Runtime and platform

Node.js v24.22.1; Darwin 27.0.0, arm64. The built CLI ran locally with isolated HOME/XDG directories. No disassembler, analysis provider, Windows runtime, or target execution was involved.

Target and artifact context

Self-authored PE32 structural fixtures: 512-byte headers and an eight-byte-aligned overlay table with one type-2 WIN_CERTIFICATE. Its definite-length ContentInfo/SignedData holds 2, 200, 400, or 600 structural X.509 certificates, each with a positive serial, UTF8String issuer/subject, validity fields, SPKI and signatureValue, plus one non-empty SignerInfo. Key and signature bytes are inert placeholders, without a claim of cryptographic validity. Encoded payload lengths are 448, 32089, 64489, and 96893 bytes respectively.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

The public CLI replay above produced this error excerpt for both 400-certificate attempts:

{
  "code": "invalid_request",
  "category": "invalid_input",
  "retryable": false,
  "recovery": {
    "kind": "inspect_input_contract",
    "operation": "inspect_pe_certificates"
  },
  "details": {
    "operation": "inspect_pe_certificates",
    "issues": [{
      "path": ["path"],
      "reason": "invalid_format",
      "message": "PKCS#7 signedData is malformed: Certificate text exceeds the 65536-byte decoded budget."
    }]
  }
}

Both 600-certificate attempts returned the same classification with this issue message:

PKCS#7 signedData is malformed: ASN.1 value count exceeds the 16384-node budget.

The complete refusal remediation was:

Read the declared input schema or CLI usage for inspect_pe_certificates; if using MCP and the catalog may be stale, call tools/list. Correct the listed fields, then retry. Do not repeat the unchanged call.

The 2- and 200-certificate controls returned coverage.status: "complete", examined_entries: 1, and certificates: 2 or 200 respectively.

Expected source at the stated baseline:

  • docs/pe-certificates.md:46-73 documents the fixed decoded-text allowance, bounded structural scope, and absence of signature verification.
  • src/domain/analysisErrorCore.ts:24-48 distinguishes resource failures from malformed input, defines bounded admission refusal, and carries fixed decoder allowance recovery. src/domain/fixedAllowanceRemediation.ts:1-25,59-71 supplies deterministic fixed-parser recovery and non-retryability. docs/error-contract.schema.json:507-570 supplies the public resource-constraint envelope.
  • src/domain/asn1Ber.ts:14-19,55-60 explicitly classifies exhausted nodes as budget-exceeded with a numeric limit.
  • src/domain/native/peCertificates.ts:39-60 exposes only path, file-byte, and table-entry request fields.

Failure source at the same baseline:

  • src/native/pe/PeCertificateAsn1.ts:48-55 discards the shared reader's failure kind and numeric limit. :72-85 reports decoded-text exhaustion through the same untagged failure type.
  • src/native/pe/PeCertificateParser.ts:107-123,171-174 reaches both failures through supported type-2 inspection and labels them malformed. Its :16-18 helper makes them format failures.
  • src/native/pe/PeCertificatesProvider.ts:144-151 maps that reason to an invalid-input path issue.

Supplemental executed source-owner probe: with a larger node allowance only for the probe, the unchanged BER reader consumed each payload exactly and counted 89, 6029, 12029, and 18029 nodes, all at maximum depth 9. The unchanged certificate decoder accepted every embedded certificate individually. With its standard 16384-node allowance, the reader returned explicit budget-exceeded/limit 16384 on the 600-certificate payload. These checks establish structural framing and certificate-field premises; they do not establish a public decoder-limit override or cryptographic validity.

Typed outcome or recovery expected

code: "resource_constraint", category resource_constraint, retryable: false, and structured limits identifying decoded-text bytes or ASN.1 nodes. Recovery should describe the exhausted fixed allowance rather than ask for request-schema corrections. The precise resource subtype and field names can follow the existing error contract; changing the allowance or returning partial success is not requested.

Analysis or suspected cause

Source-derived explanation: the PE-specific ASN.1 boundary erases the shared reader's resource tag. Text-budget exhaustion also uses the generic certificate ASN.1 error. The table parser then converts both to a format failure, which the provider projects as invalid input. Keeping the refusal reason typed through these boundaries is a possible correction; no implementation or restoration test was performed.

Additional context

Open and closed issues and PRs were searched for certificate budgets, PKCS#7 malformed failures, PE resource constraints, and the exact two allowance messages. No duplicate was found. Closed #6574 addresses BER indefinite-length support; this reproduction uses definite lengths. Closed #6694 addresses counted WIN_CERTIFICATE padding, and closed #6709 addresses TeletexString names. Open PR #7160 raises the nesting-depth allowance and explicitly leaves failure classification unchanged; these fixtures have depth 9 and exhaust different allowances. Closed #5556 concerns recovery advice for other refusals already classified as resource constraints. No last-known-good or first-bad revision was established.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The executed CLI returns an invalid-input category and input-contract recovery for two fixed decoder-capacity refusals, losing the distinction already represented by the shared reader and semantic error contract. The refusal itself and its non-retryable flag remain correct; no downstream incident is claimed.
  • Workaround status: unverified
  • Workaround basis: No same-artifact public workflow was demonstrated that preserves the intended inventory while returning the correct refusal. The strict input schema has no internal text/node override; reducing embedded certificates changes the selected artifact.
Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7531 ### 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 Native analysis or decompilation ### Observed behavior `node scripts/rea.mjs inspect-pe-certificates "$WORK/certs-400.exe" --json` refuses a synthetic certificate table with `code: "invalid_request"`, `category: "invalid_input"`, and a `path` issue with reason `invalid_format`, although its diagnostic identifies exhaustion of the fixed decoded-text budget. Recovery tells the caller to inspect the input schema and correct request fields. The same happens for the ASN.1 node budget with `certs-600.exe`. The refusal itself is expected at the fixed allowance. The incorrect behavior is treating the exhausted decoder allowance as malformed PKCS#7 and request-field invalidity. Both failures already correctly report `retryable: false`. Smaller fixtures generated by the same procedure return complete certificate inventories. ### Reproduction 1. Use the source revision below with its prepared build, locked dependencies, and Node.js v24.22.1. From the checkout root, run this complete fixture generator and public CLI replay. It uses Python-free, inert, definite-length CMS structures; no target binary executes. For a clean environment, unset any pre-existing `REA_*`, `HOPPER_*`, `GHIDRA_*`, and `NODE_OPTIONS` overrides before running. ```sh WORK="$(mktemp -d)" export WORK export HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config" \ XDG_DATA_HOME="$WORK/data" XDG_CACHE_HOME="$WORK/cache" \ XDG_STATE_HOME="$WORK/state" XDG_RUNTIME_DIR="$WORK/runtime" mkdir -p "$HOME" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" \ "$XDG_CACHE_HOME" "$XDG_STATE_HOME" "$XDG_RUNTIME_DIR" cat > "$WORK/make.mjs" <<'JS' import { writeFileSync } from 'node:fs'; import { join } from 'node:path'; const out = process.argv[2]; function value(tag, ...parts) { const body = Buffer.concat(parts.map(p => typeof p === 'string' ? Buffer.from(p) : p)); let n = body.length; const octets = []; do { octets.unshift(n & 255); n = Math.floor(n / 256); } while (n); const size = body.length < 128 ? [body.length] : [128 + octets.length, ...octets]; return Buffer.concat([Buffer.from([tag, ...size]), body]); } const sequence = (...v) => value(0x30, ...v); const set = (...v) => value(0x31, ...v); const int = n => { const bytes = []; do { bytes.unshift(n & 255); n = Math.floor(n / 256); } while (n); if (bytes[0] >= 128) bytes.unshift(0); return value(2, Buffer.from(bytes)); }; const oid = hex => value(6, Buffer.from(hex, 'hex')); const algorithm = hex => sequence(oid(hex), value(5)); const sha256 = algorithm('608648016503040201'); const rsaSha256 = algorithm('2a864886f70d01010b'); const name = i => sequence(set(sequence(oid('550403'), value(12, `Verifier ${i}`)))); const bitString = s => value(3, Buffer.from([0]), s); function certificate(i) { return sequence(sequence( value(0xa0, int(2)), int(i + 1), rsaSha256, name(i), sequence(value(23, '250101000000Z'), value(23, '260101000000Z')), name(i), sequence(algorithm('2a864886f70d010101'), bitString('key')) ), rsaSha256, bitString('signature')); } function cms(count) { const signer = sequence(int(1), sequence(name(0), int(1)), sha256, rsaSha256, value(4, 'signature')); const certificates = Array.from({length: count}, (_, i) => certificate(i)); return sequence(oid('2a864886f70d010702'), value(0xa0, sequence( int(1), set(sha256), sequence(oid('2a864886f70d010701')), value(0xa0, ...certificates), set(signer)))); } function image(payload) { const length = payload.length + 8; const table = Buffer.alloc(Math.ceil(length / 8) * 8); table.writeUInt32LE(length, 0); table.writeUInt16LE(0x200, 4); table.writeUInt16LE(2, 6); payload.copy(table, 8); const headers = Buffer.alloc(512); headers.write('MZ'); headers.writeUInt32LE(128, 60); headers.write('PE\0\0', 128); headers.writeUInt16LE(0x14c, 132); headers.writeUInt16LE(1, 134); headers.writeUInt16LE(224, 148); headers.writeUInt16LE(0x10b, 152); headers.writeUInt32LE(512, 212); headers.writeUInt32LE(16, 244); headers.writeUInt32LE(512, 280); headers.writeUInt32LE(table.length, 284); return Buffer.concat([headers, table]); } for (const count of [2, 200, 400, 600]) { const payload = cms(count); writeFileSync(join(out, `certs-${count}.exe`), image(payload)); writeFileSync(join(out, `certs-${count}.p7b`), payload); console.log(JSON.stringify({count, payloadBytes: payload.length, fileBytes: image(payload).length})); } JS node "$WORK/make.mjs" "$WORK" for count in 2 200 400 600; do for attempt in 1 2; do node scripts/rea.mjs inspect-pe-certificates "$WORK/certs-$count.exe" --json \ > "$WORK/result-$count-$attempt.json" 2> "$WORK/stderr-$count-$attempt.txt" printf 'certificates=%s attempt=%s exit=%s\n' "$count" "$attempt" "$?" done done node --input-type=module <<'JS' import {readFileSync} from 'node:fs'; for (const count of [2,200,400,600]) { const result = JSON.parse(readFileSync(`${process.env.WORK}/result-${count}-1.json`)); console.log(JSON.stringify({count, coverage: result.normalized_result?.coverage, code: result.code, category: result.category, retryable: result.retryable, recovery: result.recovery, issues: result.details?.issues})); } JS ``` 2. Observe exit 0 and complete coverage with 2 and 200 certificates. Both 400-certificate calls exit 1 with the decoded-text-budget diagnostic; both 600-certificate calls exit 1 with the node-budget diagnostic. Each failure has the invalid-input classification and input-contract recovery shown below. All eight calls had empty stderr. This exact inline procedure was replayed once during verification, with two calls per input. The same final fixtures had also produced these results in an earlier independent CLI replay. ### Expected behavior Keep the bounded refusal and the existing no-partial-success behavior. Report an exhausted fixed decoder allowance as a non-retryable `resource_constraint`, naming the applicable allowance and numeric limit, with recovery explaining that the allowance is fixed. A request-field correction cannot raise it. The documented operation performs bounded structural inspection and explicitly gives decoded certificate fields a shared 64 KiB budget. The shared semantic error contract distinguishes bounded resource admission refusals from malformed input and provides recovery for fixed decoder allowances. This expectation does not require accepting larger payloads, raising the limits, validating signatures, or returning partial inventories. ### Impact and scope P2: callers receive the wrong machine-readable failure category and recovery discriminator for two deterministic decoder-capacity refusals. The observed error identifies the selected path as invalid format instead of preserving resource exhaustion. No downstream automated retry loop or incorrect successful analysis was observed. The tested scope is four synthetic PE32 files with one type-2 WIN_CERTIFICATE each. The 400-certificate file is 65016 bytes and the 600-certificate file is 97416 bytes, both far below the default 64 MiB file-read budget and using only one of the default eight table entries. The complete inventory is unavailable on refusal, as intended by the bounded operation; the report concerns classification and recovery rather than that intentional lack of partial output. NOT_ENOUGH_INFO: prevalence in real signed binaries, a same-artifact public workaround, and downstream caller consequences were not established. The strict request schema exposes file-byte and table-entry limits, with no override for these decoder allowances. Signature validity and Windows trust acceptance were not tested or asserted. ### REA version Exact `node scripts/rea.mjs --version` output: ```text 6.8.0 ``` Source commit: `65f1c447344a423fa2785847dbcea1e9a9e2454a`. ### Runtime and platform Node.js v24.22.1; Darwin 27.0.0, arm64. The built CLI ran locally with isolated HOME/XDG directories. No disassembler, analysis provider, Windows runtime, or target execution was involved. ### Target and artifact context Self-authored PE32 structural fixtures: 512-byte headers and an eight-byte-aligned overlay table with one type-2 WIN_CERTIFICATE. Its definite-length ContentInfo/SignedData holds 2, 200, 400, or 600 structural X.509 certificates, each with a positive serial, UTF8String issuer/subject, validity fields, SPKI and signatureValue, plus one non-empty SignerInfo. Key and signature bytes are inert placeholders, without a claim of cryptographic validity. Encoded payload lengths are 448, 32089, 64489, and 96893 bytes respectively. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence The public CLI replay above produced this error excerpt for both 400-certificate attempts: ```json { "code": "invalid_request", "category": "invalid_input", "retryable": false, "recovery": { "kind": "inspect_input_contract", "operation": "inspect_pe_certificates" }, "details": { "operation": "inspect_pe_certificates", "issues": [{ "path": ["path"], "reason": "invalid_format", "message": "PKCS#7 signedData is malformed: Certificate text exceeds the 65536-byte decoded budget." }] } } ``` Both 600-certificate attempts returned the same classification with this issue message: ```text PKCS#7 signedData is malformed: ASN.1 value count exceeds the 16384-node budget. ``` The complete refusal remediation was: ```text Read the declared input schema or CLI usage for inspect_pe_certificates; if using MCP and the catalog may be stale, call tools/list. Correct the listed fields, then retry. Do not repeat the unchanged call. ``` The 2- and 200-certificate controls returned `coverage.status: "complete"`, `examined_entries: 1`, and `certificates: 2` or `200` respectively. Expected source at the stated baseline: - `docs/pe-certificates.md:46-73` documents the fixed decoded-text allowance, bounded structural scope, and absence of signature verification. - `src/domain/analysisErrorCore.ts:24-48` distinguishes resource failures from malformed input, defines bounded admission refusal, and carries fixed decoder allowance recovery. `src/domain/fixedAllowanceRemediation.ts:1-25,59-71` supplies deterministic fixed-parser recovery and non-retryability. `docs/error-contract.schema.json:507-570` supplies the public resource-constraint envelope. - `src/domain/asn1Ber.ts:14-19,55-60` explicitly classifies exhausted nodes as `budget-exceeded` with a numeric limit. - `src/domain/native/peCertificates.ts:39-60` exposes only path, file-byte, and table-entry request fields. Failure source at the same baseline: - `src/native/pe/PeCertificateAsn1.ts:48-55` discards the shared reader's failure kind and numeric limit. `:72-85` reports decoded-text exhaustion through the same untagged failure type. - `src/native/pe/PeCertificateParser.ts:107-123,171-174` reaches both failures through supported type-2 inspection and labels them malformed. Its `:16-18` helper makes them format failures. - `src/native/pe/PeCertificatesProvider.ts:144-151` maps that reason to an invalid-input path issue. Supplemental executed source-owner probe: with a larger node allowance only for the probe, the unchanged BER reader consumed each payload exactly and counted 89, 6029, 12029, and 18029 nodes, all at maximum depth 9. The unchanged certificate decoder accepted every embedded certificate individually. With its standard 16384-node allowance, the reader returned explicit `budget-exceeded`/limit `16384` on the 600-certificate payload. These checks establish structural framing and certificate-field premises; they do not establish a public decoder-limit override or cryptographic validity. ### Typed outcome or recovery expected `code: "resource_constraint"`, category `resource_constraint`, `retryable: false`, and structured limits identifying decoded-text bytes or ASN.1 nodes. Recovery should describe the exhausted fixed allowance rather than ask for request-schema corrections. The precise resource subtype and field names can follow the existing error contract; changing the allowance or returning partial success is not requested. ### Analysis or suspected cause Source-derived explanation: the PE-specific ASN.1 boundary erases the shared reader's resource tag. Text-budget exhaustion also uses the generic certificate ASN.1 error. The table parser then converts both to a format failure, which the provider projects as invalid input. Keeping the refusal reason typed through these boundaries is a possible correction; no implementation or restoration test was performed. ### Additional context Open and closed issues and PRs were searched for certificate budgets, PKCS#7 malformed failures, PE resource constraints, and the exact two allowance messages. No duplicate was found. Closed [#6574](https://github.com/morluto/rea/issues/6574) addresses BER indefinite-length support; this reproduction uses definite lengths. Closed [#6694](https://github.com/morluto/rea/issues/6694) addresses counted WIN_CERTIFICATE padding, and closed [#6709](https://github.com/morluto/rea/issues/6709) addresses TeletexString names. Open [PR #7160](https://github.com/morluto/rea/pull/7160) raises the nesting-depth allowance and explicitly leaves failure classification unchanged; these fixtures have depth 9 and exhaust different allowances. Closed [#5556](https://github.com/morluto/rea/issues/5556) concerns recovery advice for other refusals already classified as resource constraints. No last-known-good or first-bad revision was established. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The executed CLI returns an invalid-input category and input-contract recovery for two fixed decoder-capacity refusals, losing the distinction already represented by the shared reader and semantic error contract. The refusal itself and its non-retryable flag remain correct; no downstream incident is claimed. - Workaround status: unverified - Workaround basis: No same-artifact public workflow was demonstrated that preserves the intended inventory while returning the correct refusal. The strict input schema has no internal text/node override; reducing embedded certificates changes the selected artifact.
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#4474
No description provided.