From ab288fffcb504acd62d4386ec1540e1284b15431 Mon Sep 17 00:00:00 2001 From: sb-rohitdesai Date: Thu, 29 Jan 2026 17:24:48 +0530 Subject: [PATCH] fix: issue of simple-eval security issue is fixed --- packages/core/package.json | 2 +- packages/core/src/utils/replacer.ts | 44 ++++++++++++++++++++--------- yarn.lock | 18 ++++++------ 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/packages/core/package.json b/packages/core/package.json index d28e63497..af98aa684 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -47,13 +47,13 @@ "ajv-errors": "~3.0.0", "ajv-formats": "~2.1.1", "es-aggregate-error": "^1.0.7", + "expr-eval-fork": "^3.0.1", "jsonpath-plus": "^10.3.0", "lodash": "~4.17.21", "lodash.topath": "^4.5.2", "minimatch": "3.1.2", "nimma": "0.2.3", "pony-cause": "^1.1.1", - "simple-eval": "1.0.1", "tslib": "^2.8.1" }, "devDependencies": { diff --git a/packages/core/src/utils/replacer.ts b/packages/core/src/utils/replacer.ts index cee00d1f8..a8a0df170 100644 --- a/packages/core/src/utils/replacer.ts +++ b/packages/core/src/utils/replacer.ts @@ -1,5 +1,5 @@ import { Dictionary } from '@stoplight/types'; -import _eval from 'simple-eval'; +import { Parser, Value } from 'expr-eval-fork'; export type Transformer> = (this: V, ...args: unknown[]) => string; @@ -18,28 +18,44 @@ export class Replacer> { } public print(input: string, values: V): string { - return input.replace(this.regex, (substr, identifier, index) => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const parser = new Parser(); + const functions = parser.functions as Record Value>; + functions.toUpperCase = (value: Value): Value => { + return String(value).toUpperCase(); + }; + + functions.concat = (...args: Value[]): Value => { + return args.map(String).join(''); + }; + + Object.entries(this.functions).forEach(([name, fn]) => { + functions[name] = fn.bind(values) as (...args: Value[]) => Value; + }); + + const context = values as unknown as Record; + + return input.replace(this.regex, (_substr, identifier: string, index: number) => { + if (index < 0 || index >= input.length) { + return ''; + } + const shouldEvaluate = input[index] === '#'; if (shouldEvaluate) { - return String( - _eval(identifier, { - ...Object.entries(this.functions).reduce((fns, [name, fn]) => { - fns[name] = fn.bind(values); - return fns; - }, {}), - ...values, - }), - ); + const expression = identifier + .trim() + .replace(/(\S+)\.toUpperCase\(\)/g, 'toUpperCase($1)') + .replace(/\s*\+\s*/g, ',') + .replace(/^(.+)$/, 'concat($1)'); + + return String(parser.evaluate(expression, context)); } if (!(identifier in values)) { return ''; } - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - return String(values[identifier]); + return String(values[identifier as keyof V]); }); } } diff --git a/yarn.lock b/yarn.lock index 1320f1a09..46e69d32b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2984,6 +2984,7 @@ __metadata: ajv-errors: ~3.0.0 ajv-formats: ~2.1.1 es-aggregate-error: ^1.0.7 + expr-eval-fork: ^3.0.1 jsonpath-plus: ^10.3.0 lodash: ~4.17.21 lodash.topath: ^4.5.2 @@ -2991,7 +2992,6 @@ __metadata: nimma: 0.2.3 nock: ^13.5.4 pony-cause: ^1.1.1 - simple-eval: 1.0.1 treeify: ^1.1.0 tslib: ^2.8.1 languageName: unknown @@ -6844,6 +6844,13 @@ __metadata: languageName: node linkType: hard +"expr-eval-fork@npm:^3.0.1": + version: 3.0.1 + resolution: "expr-eval-fork@npm:3.0.1" + checksum: 8841b2a521415cecd15cb860078ffe99678c59ab427a50c033f91426db12dff6450c72bb0a3f8bbe5c7125a83ccfab47209411b46cf0da5acbb4cf97c91eb362 + languageName: node + linkType: hard + "ext@npm:^1.1.2": version: 1.4.0 resolution: "ext@npm:1.4.0" @@ -12627,15 +12634,6 @@ __metadata: languageName: node linkType: hard -"simple-eval@npm:1.0.1": - version: 1.0.1 - resolution: "simple-eval@npm:1.0.1" - dependencies: - jsep: ^1.3.6 - checksum: 280207cfe4538c500f6b41e4d88576cf250337b0042bec8f9f5cf025b3a70e07974e522edd01e69d378767dd73068765d4f46ad55db5c94943c8f3585bff95af - languageName: node - linkType: hard - "simple-get@npm:^4.0.0": version: 4.0.1 resolution: "simple-get@npm:4.0.1"