Skip to content

Commit 099e569

Browse files
fix: address PR feedback - make ShadowRealm usage correct
- Add TypeScript type declaration for ShadowRealm (Stage 3 proposal) - Make safeEvaluateMath synchronous (evaluate() is sync per TC39 spec) - Add input validation regex to only allow safe math characters - Remove unnecessary parentheses wrapping around expression - Add note about DoS vectors not being prevented by ShadowRealm Co-Authored-By: Tom Aylott <thomas.42@gmail.com>
1 parent 2987e7f commit 099e569

File tree

1 file changed

+24
-9
lines changed

1 file changed

+24
-9
lines changed

examples/tools-example.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ import * as dotenv from 'dotenv';
2323
import { z } from 'zod/v4';
2424
import { OpenRouter, ToolType } from '../src/index.js';
2525

26+
// Type declaration for ShadowRealm (TC39 Stage 3 proposal)
27+
// See: https://tc39.es/proposal-shadowrealm/
28+
declare class ShadowRealm {
29+
constructor();
30+
evaluate(sourceText: string): unknown;
31+
importValue(specifier: string, bindingName: string): Promise<unknown>;
32+
}
33+
2634
dotenv.config();
2735

2836
const client = new OpenRouter({
@@ -168,21 +176,28 @@ async function generatorToolExample() {
168176
*
169177
* ShadowRealm provides a secure, isolated JavaScript execution environment
170178
* that prevents access to the host realm's globals (no access to DOM, fetch,
171-
* filesystem, etc.). This makes it safe for evaluating untrusted expressions.
179+
* filesystem, etc.). Combined with input validation, this makes it safe for
180+
* evaluating untrusted math expressions.
181+
*
182+
* Note: ShadowRealm isolates from host APIs but does not prevent DoS vectors
183+
* like infinite loops. For production use, consider additional safeguards.
172184
*
173185
* Browser support: Chrome 124+, Edge 124+, Firefox 128+, Safari 18+
174186
* Node.js support: Available behind --experimental-shadow-realm flag (v19+)
175187
* See: https://tc39.es/proposal-shadowrealm/
176188
*/
177-
async function safeEvaluateMath(expression: string): Promise<number> {
178-
// ShadowRealm is a TC39 Stage 3 proposal for isolated JavaScript execution
179-
// It creates a separate realm with its own global object, preventing access
180-
// to the host environment's APIs (no DOM, no Node.js APIs, no fetch, etc.)
189+
function safeEvaluateMath(expression: string): number {
190+
// Only allow digits, whitespace, basic operators, decimal point, and parentheses
191+
if (!/^[\d\s+\-*/.()]+$/.test(expression)) {
192+
throw new Error('Expression contains invalid characters');
193+
}
194+
195+
// ShadowRealm creates a separate realm with its own global object, preventing
196+
// access to the host environment's APIs (no DOM, no Node.js APIs, no fetch, etc.)
181197
const realm = new ShadowRealm();
182198

183-
// The expression is evaluated in complete isolation - even if malicious code
184-
// is injected, it cannot access anything outside the shadow realm
185-
const result = await realm.evaluate(`(${expression})`);
199+
// The expression is evaluated in complete isolation
200+
const result = realm.evaluate(expression);
186201

187202
if (typeof result !== 'number' || !Number.isFinite(result)) {
188203
throw new Error('Expression did not evaluate to a finite number');
@@ -233,7 +248,7 @@ async function manualToolExample() {
233248

234249
// Safely evaluate the math expression using ShadowRealm
235250
try {
236-
const _result = await safeEvaluateMath(expression);
251+
const _result = safeEvaluateMath(expression);
237252
} catch (_error) {}
238253
}
239254
}

0 commit comments

Comments
 (0)