fix(artifacts): validate Godot row extent before budget (#9638)

This commit is contained in:
morluto authored and GitHub committed 2026-11-09 20:56:01 +08:00
1 parent b394d50943
commit 35fbec9df5
2 files changed
+16 -2

No files matched your search

+11 -1
View File
@@ -234,9 +234,19 @@ describe("GodotPckArtifactReader", () => {
});
});
it("rejects oversized encoded path metadata before allocating its declared bytes", async () => {
it("reports an oversized path that cannot fit in the pack as malformed", async () => {
const bytes = buildGodotPck(2, members);
bytes.writeUInt32LE(0xffff_ffff, 100);
await withReader(bytes, async (reader) => {
await expect(list(reader)).rejects.toMatchObject({
reason: "format",
});
});
});
it("refuses a fully framed path over the metadata budget", async () => {
const path = "a".repeat(Math.floor((64 * 1024 * 1024) / 18) + 1);
const bytes = buildGodotPck(2, [{ path, data: "" }]);
await withReader(bytes, async (reader) => {
await expect(list(reader)).rejects.toMatchObject({
reason: "limit",
+5 -1
View File
@@ -91,6 +91,7 @@ export class GodotPckArtifactReader extends PositionalArtifactReader {
if (index % 256 === 0) await setImmediate();
assertArtifactReadActive(signal);
const pathBytes = await cursor.uint32();
cursor.requireBytes(pathBytes + (header.format_version === 1 ? 32 : 36));
// Check worst-case JSON escaping before decoding or allocating the path.
// The logical path, raw source path, and metadata source path can each
// need six JSON bytes per input byte before retained facts are charged.
@@ -274,9 +275,12 @@ class PckCursor {
private readonly end: number,
private readonly signal?: AbortSignal,
) {}
async bytes(length: number): Promise<Buffer> {
requireBytes(length: number): void {
if (length > this.end - this.position)
throw formatFailure("directory entry exceeds the pack");
}
async bytes(length: number): Promise<Buffer> {
this.requireBytes(length);
if (length > MAX_DIRECTORY_METADATA_BYTES / 18) throw metadataLimit();
if (length > DIRECTORY_CHUNK_BYTES) {
// A large valid virtual path is bounded by retained representation, not