mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
fix(web-runtime): cap sanitize recursion to prevent stack overflow
State exposes document and window (per WebState in types.ts). A user extractor returning either crashes the runtime via stack overflow on the circular DOM/Window references. Track seen objects in a WeakSet and bail at depth 32 so the worst case becomes a truncated value, not a process kill.
This commit is contained in:
1 parent
fc1e6f9319
commit
9722839339
1 file changed
+18
-5
@@ -380,21 +380,34 @@ function evaluateExtractors(): Record<number, unknown> {
|
||||
return result;
|
||||
}
|
||||
|
||||
// SANITIZE_MAX_DEPTH bounds how far sanitize will recurse. State exposes
|
||||
// `document` and `window`, both of which contain cycles; without a depth or
|
||||
// seen-set guard a user extractor returning either crashes the runtime via
|
||||
// stack overflow.
|
||||
const SANITIZE_MAX_DEPTH = 32;
|
||||
|
||||
function sanitize(value: unknown): unknown {
|
||||
return sanitizeAt(value, 0, new WeakSet());
|
||||
}
|
||||
|
||||
function sanitizeAt(value: unknown, depth: number, seen: WeakSet<object>): unknown {
|
||||
if (value === null || value === undefined) return value;
|
||||
if (typeof value === "function") return undefined;
|
||||
if (Array.isArray(value)) return value.map(sanitize);
|
||||
if (typeof value === "object") {
|
||||
if (typeof value !== "object") return value;
|
||||
if (depth >= SANITIZE_MAX_DEPTH) return null;
|
||||
if (seen.has(value as object)) return null;
|
||||
seen.add(value as object);
|
||||
if (Array.isArray(value)) {
|
||||
return value.map((item) => sanitizeAt(item, depth + 1, seen));
|
||||
}
|
||||
const out: Record<string, unknown> = {};
|
||||
for (const key of Object.keys(value as Record<string, unknown>)) {
|
||||
const sub = (value as Record<string, unknown>)[key];
|
||||
if (typeof sub === "function") continue;
|
||||
out[key] = sanitize(sub);
|
||||
out[key] = sanitizeAt(sub, depth + 1, seen);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function pickWeighted(handle: ActionGeneratorHandle): ActionGeneratorHandle | null {
|
||||
const entries = handle.entries ?? [];
|
||||
|
||||
Reference in new issue
Block a user