diff --git a/.changeset/no-eval-in-revive.md b/.changeset/no-eval-in-revive.md new file mode 100644 index 0000000000..71b8c5fbeb --- /dev/null +++ b/.changeset/no-eval-in-revive.md @@ -0,0 +1,5 @@ +--- +"@workflow/core": patch +--- + +Replace `eval` in `serialization.ts` `revive()` helper with `JSON.parse`. `devalue.stringify()` output is always valid JSON (special values are encoded as negative integer sentinels), so `JSON.parse` is a safe drop-in that eliminates the `eval` anti-pattern. diff --git a/packages/core/src/serialization.ts b/packages/core/src/serialization.ts index c16b04f310..430cf10507 100644 --- a/packages/core/src/serialization.ts +++ b/packages/core/src/serialization.ts @@ -675,9 +675,11 @@ type Revivers = { }; function revive(str: string) { - // biome-ignore lint/security/noGlobalEval: Eval is safe here - we are only passing value from `devalue.stringify()` - // biome-ignore lint/complexity/noCommaOperator: This is how you do global scope eval - return (0, eval)(`(${str})`); + // devalue.stringify() always produces valid JSON: special values + // (undefined, NaN, Infinity, -0) are encoded as negative integer + // sentinels and the remaining structure is ordinary JSON. Parsing + // with JSON.parse yields the flattened form that unflatten() expects. + return JSON.parse(str); } function getCommonReducers(global: Record = globalThis) {