From 8e48b4a53cca7d5faae5f188288bb4d713b21e40 Mon Sep 17 00:00:00 2001 From: Pranay Prakash Date: Thu, 23 Apr 2026 17:37:02 -0700 Subject: [PATCH 1/2] Replace eval with JSON.parse in serialization revive helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit devalue.stringify() always produces valid JSON — special values (undefined, NaN, Infinity, -0) are encoded as negative integer sentinels. JSON.parse yields the same flattened array form that unflatten() expects, without the eval anti-pattern (VULN-918). Co-Authored-By: Claude Opus 4.7 --- .changeset/no-eval-in-revive.md | 6 ++++++ packages/core/src/serialization.ts | 8 +++++--- 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 .changeset/no-eval-in-revive.md diff --git a/.changeset/no-eval-in-revive.md b/.changeset/no-eval-in-revive.md new file mode 100644 index 0000000000..56f691ec7c --- /dev/null +++ b/.changeset/no-eval-in-revive.md @@ -0,0 +1,6 @@ +--- +"@workflow/core": patch +"workflow": 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) { From e2da6188501d194fddf17de23b9bd49e58780a67 Mon Sep 17 00:00:00 2001 From: Pranay Prakash Date: Thu, 23 Apr 2026 17:39:13 -0700 Subject: [PATCH 2/2] Drop redundant workflow package from changeset Co-Authored-By: Claude Opus 4.7 --- .changeset/no-eval-in-revive.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.changeset/no-eval-in-revive.md b/.changeset/no-eval-in-revive.md index 56f691ec7c..71b8c5fbeb 100644 --- a/.changeset/no-eval-in-revive.md +++ b/.changeset/no-eval-in-revive.md @@ -1,6 +1,5 @@ --- "@workflow/core": patch -"workflow": 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.