mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
fix(artifacts): classify ZIP offsets beyond EOF as malformed
Reject negative bounded reads before allocation while retaining short-read and exact-EOF behavior. Exercise the corrupted central-directory offset through the public CLI. Refs #4006, #3953 Co-authored-by: jackie_cqz <88996311+jackie-cqz@users.noreply.github.com>
This commit is contained in:
@@ -127,6 +127,13 @@ class NodeFileReader extends Reader<string> {
|
||||
const handle = this.#handle;
|
||||
if (handle === undefined) throw new Error("ZIP reader is not initialized");
|
||||
const readBytes = Math.min(length, this.size - index);
|
||||
// A central-directory offset can point past EOF. Type that malformed ZIP
|
||||
// read before a negative size reaches Buffer.alloc and becomes an I/O error.
|
||||
if (readBytes < 0)
|
||||
throw new ArtifactReaderFailure(
|
||||
"format",
|
||||
`ZIP archive is malformed: read at ${index} extends beyond the ${this.size}-byte archive`,
|
||||
);
|
||||
if (
|
||||
this.maximumReadBytes !== undefined &&
|
||||
readBytes > this.maximumReadBytes
|
||||
|
||||
@@ -13,6 +13,37 @@ import { parseEvidence } from "../../src/domain/evidence.js";
|
||||
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
|
||||
import { cliTest } from "../support/cli/cliFixture.js";
|
||||
|
||||
cliTest(
|
||||
"classifies a ZIP local-header offset beyond EOF as malformed input",
|
||||
async ({ cli }) => {
|
||||
const root = await createTestTempDirectory("rea-zip-beyond-eof-");
|
||||
const archivePath = join(root, "beyond-eof.zip");
|
||||
const writer = new ZipWriter(new Uint8ArrayWriter());
|
||||
await writer.add("member.bin", new TextReader("valid member bytes"));
|
||||
const bytes = Buffer.from(await writer.close());
|
||||
const central = bytes.indexOf(Buffer.from([0x50, 0x4b, 0x01, 0x02]));
|
||||
if (central < 0) throw new Error("Expected a ZIP central directory");
|
||||
bytes.writeUInt32LE(bytes.length + 1024, central + 42);
|
||||
await writeFile(archivePath, bytes);
|
||||
|
||||
const result = await cli.run({
|
||||
arguments: ["inspect-artifact", archivePath, "--json"],
|
||||
});
|
||||
expect(result.exitCode, result.stdout + result.stderr).toBe(1);
|
||||
expect(result.json).toMatchObject({
|
||||
code: "artifact_operation_failed",
|
||||
category: "execution_failure",
|
||||
message:
|
||||
"Artifact is invalid or has changed. Get a fresh copy and try again.",
|
||||
details: {
|
||||
operation: "inspect_artifact",
|
||||
reason: "format",
|
||||
detail: expect.stringContaining("extends beyond"),
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
cliTest(
|
||||
"inspects and extracts ZIP members with repeated current-directory prefixes",
|
||||
async ({ cli }) => {
|
||||
|
||||
Reference in New Issue
Block a user