diff --git a/packages/kv/src/namespace.ts b/packages/kv/src/namespace.ts index 14518cd91..439d86e14 100644 --- a/packages/kv/src/namespace.ts +++ b/packages/kv/src/namespace.ts @@ -16,6 +16,8 @@ import { } from "@miniflare/shared"; const MIN_CACHE_TTL = 60; /* 60s */ +const MIN_EXPIRATION = -2147483648; /* Minimum signed 32-bit integer */ +const MAX_EXPIRATION = 2147483647; /* Maximum signed 32-bit integer */ const MAX_LIST_KEYS = 1000; const MAX_KEY_SIZE = 512; /* 512B */ const MAX_VALUE_SIZE = 25 * 1024 * 1024; /* 25MiB */ @@ -289,6 +291,12 @@ export class KVNamespace { let expiration = normaliseInt(options.expiration); const expirationTtl = normaliseInt(options.expirationTtl); if (expirationTtl !== undefined) { + if (expirationTtl < MIN_EXPIRATION || expirationTtl > MAX_EXPIRATION) { + // Workers throws like this without the extra sugar when the value is out of bounds, and throws before checking the value itself. + throw new TypeError( + `Value out of range. Must be between ${MIN_EXPIRATION} and ${MAX_EXPIRATION} (inclusive).` + ); + } if (isNaN(expirationTtl) || expirationTtl <= 0) { throwKVError( "PUT", @@ -305,6 +313,12 @@ export class KVNamespace { } expiration = now + expirationTtl; } else if (expiration !== undefined) { + if (expiration < MIN_EXPIRATION || expiration > MAX_EXPIRATION) { + // Workers throws like this without the extra sugar when the value is out of bounds, and throws before checking the value itself. + throw new TypeError( + `Value out of range. Must be between ${MIN_EXPIRATION} and ${MAX_EXPIRATION} (inclusive).` + ); + } if (isNaN(expiration) || expiration <= now) { throwKVError( "PUT", diff --git a/packages/kv/test/namespace.spec.ts b/packages/kv/test/namespace.spec.ts index 8b6b8a27f..cdcfd89c6 100644 --- a/packages/kv/test/namespace.spec.ts +++ b/packages/kv/test/namespace.spec.ts @@ -467,6 +467,16 @@ test("put: validates expiration ttl", async (t) => { message: "KV PUT failed: 400 Invalid expiration_ttl of 30. Expiration TTL must be at least 60.", }); + await t.throwsAsync(ns.put("key", "value", { expirationTtl: 2147483648 }), { + instanceOf: TypeError, + message: + "Value out of range. Must be between -2147483648 and 2147483647 (inclusive).", + }); + await t.throwsAsync(ns.put("key", "value", { expirationTtl: -2147483649 }), { + instanceOf: TypeError, + message: + "Value out of range. Must be between -2147483648 and 2147483647 (inclusive).", + }); }); test("put: validates expiration", async (t) => { const { ns } = t.context; @@ -486,6 +496,16 @@ test("put: validates expiration", async (t) => { message: "KV PUT failed: 400 Invalid expiration of 780. Expiration times must be at least 60 seconds in the future.", }); + await t.throwsAsync(ns.put("key", "value", { expiration: 2147483648 }), { + instanceOf: TypeError, + message: + "Value out of range. Must be between -2147483648 and 2147483647 (inclusive).", + }); + await t.throwsAsync(ns.put("key", "value", { expiration: -2147483649 }), { + instanceOf: TypeError, + message: + "Value out of range. Must be between -2147483648 and 2147483647 (inclusive).", + }); }); test("put: validates value size", async (t) => { const { ns } = t.context;