|
| 1 | +diff --git a/v4/core/schemas.cjs b/v4/core/schemas.cjs |
| 2 | +index 8444c1fa122b0502f56b141ffa2939906b49baf9..9a085e4beacdbe1ef84c4c6a30b471b4aa9f9625 100644 |
| 3 | +--- a/v4/core/schemas.cjs |
| 4 | ++++ b/v4/core/schemas.cjs |
| 5 | +@@ -685,6 +685,37 @@ function handleArrayResult(result, final, index) { |
| 6 | + } |
| 7 | + final.value[index] = result.value; |
| 8 | + } |
| 9 | ++// Backport of colinhacks/zod#6652 (zod 4.6.6, GHSA-mrhx-c7xc-m3w5): a container larger than |
| 10 | ++// its leading upper size bound skips its elements, so that bound's check (which has a `when` |
| 11 | ++// guard and always runs) reports it without parsing and collecting an issue per element first. |
| 12 | ++function sizeCaps(defChecks) { |
| 13 | ++ const caps = []; |
| 14 | ++ for (const ch of defChecks ?? []) { |
| 15 | ++ const d = ch._zod.def; |
| 16 | ++ // a later check may rewrite the value |
| 17 | ++ if (!/_(length|size)$|_equals$/.test(d.check)) |
| 18 | ++ break; |
| 19 | ++ const max = d.maximum ?? d.length ?? d.size; |
| 20 | ++ if (max >= 0) |
| 21 | ++ caps.push(max); |
| 22 | ++ } |
| 23 | ++ return caps; |
| 24 | ++} |
| 25 | ++function capSize(inst, size) { |
| 26 | ++ const caps = sizeCaps(inst._zod.def.checks); |
| 27 | ++ if (!caps.length) |
| 28 | ++ return; |
| 29 | ++ const cap = Math.min(...caps); |
| 30 | ++ const parse = inst._zod.parse; |
| 31 | ++ inst._zod.parse = (payload, ctx) => { |
| 32 | ++ if (size(payload.value) > cap && !ctx?.skipChecks && ctx?.direction !== "backward") |
| 33 | ++ return payload; |
| 34 | ++ return parse(payload, ctx); |
| 35 | ++ }; |
| 36 | ++} |
| 37 | ++const arraySize = (input) => (Array.isArray(input) ? input.length : -1); |
| 38 | ++const mapSize = (input) => (input instanceof Map ? input.size : -1); |
| 39 | ++const setSize = (input) => (input instanceof Set ? input.size : -1); |
| 40 | + exports.$ZodArray = core.$constructor("$ZodArray", (inst, def) => { |
| 41 | + exports.$ZodType.init(inst, def); |
| 42 | + inst._zod.parse = (payload, ctx) => { |
| 43 | +@@ -718,6 +749,7 @@ exports.$ZodArray = core.$constructor("$ZodArray", (inst, def) => { |
| 44 | + } |
| 45 | + return payload; //handleArrayResultsAsync(parseResults, final); |
| 46 | + }; |
| 47 | ++ capSize(inst, arraySize); |
| 48 | + }); |
| 49 | + function handlePropertyResult(result, final, key, input, isOptionalOut) { |
| 50 | + if (result.issues.length) { |
| 51 | +@@ -1480,6 +1512,7 @@ exports.$ZodMap = core.$constructor("$ZodMap", (inst, def) => { |
| 52 | + return Promise.all(proms).then(() => payload); |
| 53 | + return payload; |
| 54 | + }; |
| 55 | ++ capSize(inst, mapSize); |
| 56 | + }); |
| 57 | + function handleMapResult(keyResult, valueResult, final, key, input, inst, ctx) { |
| 58 | + if (keyResult.issues.length) { |
| 59 | +@@ -1540,6 +1573,7 @@ exports.$ZodSet = core.$constructor("$ZodSet", (inst, def) => { |
| 60 | + return Promise.all(proms).then(() => payload); |
| 61 | + return payload; |
| 62 | + }; |
| 63 | ++ capSize(inst, setSize); |
| 64 | + }); |
| 65 | + function handleSetResult(result, final) { |
| 66 | + if (result.issues.length) { |
| 67 | +diff --git a/v4/core/schemas.js b/v4/core/schemas.js |
| 68 | +index 29c61bc5fcf2ca90c2bb0121b7f02e16fdf19f11..f87884eea6e301f1c9c46be45953226e850e4795 100644 |
| 69 | +--- a/v4/core/schemas.js |
| 70 | ++++ b/v4/core/schemas.js |
| 71 | +@@ -654,6 +654,37 @@ function handleArrayResult(result, final, index) { |
| 72 | + } |
| 73 | + final.value[index] = result.value; |
| 74 | + } |
| 75 | ++// Backport of colinhacks/zod#6652 (zod 4.6.6, GHSA-mrhx-c7xc-m3w5): a container larger than |
| 76 | ++// its leading upper size bound skips its elements, so that bound's check (which has a `when` |
| 77 | ++// guard and always runs) reports it without parsing and collecting an issue per element first. |
| 78 | ++function sizeCaps(defChecks) { |
| 79 | ++ const caps = []; |
| 80 | ++ for (const ch of defChecks ?? []) { |
| 81 | ++ const d = ch._zod.def; |
| 82 | ++ // a later check may rewrite the value |
| 83 | ++ if (!/_(length|size)$|_equals$/.test(d.check)) |
| 84 | ++ break; |
| 85 | ++ const max = d.maximum ?? d.length ?? d.size; |
| 86 | ++ if (max >= 0) |
| 87 | ++ caps.push(max); |
| 88 | ++ } |
| 89 | ++ return caps; |
| 90 | ++} |
| 91 | ++function capSize(inst, size) { |
| 92 | ++ const caps = sizeCaps(inst._zod.def.checks); |
| 93 | ++ if (!caps.length) |
| 94 | ++ return; |
| 95 | ++ const cap = Math.min(...caps); |
| 96 | ++ const parse = inst._zod.parse; |
| 97 | ++ inst._zod.parse = (payload, ctx) => { |
| 98 | ++ if (size(payload.value) > cap && !ctx?.skipChecks && ctx?.direction !== "backward") |
| 99 | ++ return payload; |
| 100 | ++ return parse(payload, ctx); |
| 101 | ++ }; |
| 102 | ++} |
| 103 | ++const arraySize = (input) => (Array.isArray(input) ? input.length : -1); |
| 104 | ++const mapSize = (input) => (input instanceof Map ? input.size : -1); |
| 105 | ++const setSize = (input) => (input instanceof Set ? input.size : -1); |
| 106 | + export const $ZodArray = /*@__PURE__*/ core.$constructor("$ZodArray", (inst, def) => { |
| 107 | + $ZodType.init(inst, def); |
| 108 | + inst._zod.parse = (payload, ctx) => { |
| 109 | +@@ -687,6 +718,7 @@ export const $ZodArray = /*@__PURE__*/ core.$constructor("$ZodArray", (inst, def |
| 110 | + } |
| 111 | + return payload; //handleArrayResultsAsync(parseResults, final); |
| 112 | + }; |
| 113 | ++ capSize(inst, arraySize); |
| 114 | + }); |
| 115 | + function handlePropertyResult(result, final, key, input, isOptionalOut) { |
| 116 | + if (result.issues.length) { |
| 117 | +@@ -1449,6 +1481,7 @@ export const $ZodMap = /*@__PURE__*/ core.$constructor("$ZodMap", (inst, def) => |
| 118 | + return Promise.all(proms).then(() => payload); |
| 119 | + return payload; |
| 120 | + }; |
| 121 | ++ capSize(inst, mapSize); |
| 122 | + }); |
| 123 | + function handleMapResult(keyResult, valueResult, final, key, input, inst, ctx) { |
| 124 | + if (keyResult.issues.length) { |
| 125 | +@@ -1509,6 +1542,7 @@ export const $ZodSet = /*@__PURE__*/ core.$constructor("$ZodSet", (inst, def) => |
| 126 | + return Promise.all(proms).then(() => payload); |
| 127 | + return payload; |
| 128 | + }; |
| 129 | ++ capSize(inst, setSize); |
| 130 | + }); |
| 131 | + function handleSetResult(result, final) { |
| 132 | + if (result.issues.length) { |
0 commit comments