diff --git a/packages/gguf/src/gguf.ts b/packages/gguf/src/gguf.ts index b91658e4d0..1a17aa25e4 100644 --- a/packages/gguf/src/gguf.ts +++ b/packages/gguf/src/gguf.ts @@ -40,6 +40,7 @@ const MAX_STRING_LENGTH = 10_000_000; // 10MB per string (CWE-770) const MAX_TENSOR_NDIMS = 8; // GGML supports up to 4, be generous (CWE-770) const MAX_ARRAY_RECURSION_DEPTH = 4; // nested ARRAY-of-ARRAY depth limit (CWE-674) const MAX_CHUNK_FETCHES_PER_VALUE = 30; // prevent infinite fetch loop (CWE-835) +const MAX_ALIGNMENT = 1 << 30; // 2^30 — largest power-of-2 safe for JS bitwise ops (CWE-190) const GGML_PAD = (x: number, n: number) => (x + n - 1) & ~(n - 1); // defined in ggml.h const PARALLEL_DOWNLOADS = 20; @@ -505,6 +506,12 @@ export async function gguf( if (alignment <= 0 || !Number.isInteger(alignment)) { throw new Error(`general.alignment must be a positive integer, got ${rawAlignment}`); } + if ((alignment & (alignment - 1)) !== 0) { + throw new Error(`general.alignment must be a power of 2, got ${rawAlignment}`); + } + if (alignment > MAX_ALIGNMENT) { + throw new Error(`general.alignment ${rawAlignment} exceeds maximum safe value (${MAX_ALIGNMENT}) for JS bitwise operations`); + } const tensorInfoEndBeforePadOffset = offset; const tensorDataOffset = BigInt(GGML_PAD(offset, alignment)); @@ -654,6 +661,9 @@ export function serializeGgufMetadata( ): Uint8Array { const littleEndian = options.littleEndian ?? true; const alignment = options.alignment ?? GGUF_DEFAULT_ALIGNMENT; + if (alignment <= 0 || !Number.isInteger(alignment) || (alignment & (alignment - 1)) !== 0 || alignment > MAX_ALIGNMENT) { + throw new Error(`alignment must be a power of 2 in [1, ${MAX_ALIGNMENT}], got ${alignment}`); + } const version = typedMetadata.version.value; // Start with GGUF magic number: "GGUF" @@ -762,6 +772,9 @@ export async function buildGgufHeader( }, ): Promise { const alignment = options.alignment ?? GGUF_DEFAULT_ALIGNMENT; + if (alignment <= 0 || !Number.isInteger(alignment) || (alignment & (alignment - 1)) !== 0 || alignment > MAX_ALIGNMENT) { + throw new Error(`alignment must be a power of 2 in [1, ${MAX_ALIGNMENT}], got ${alignment}`); + } const version = updatedMetadata.version.value; // Serialize the new metadata