Skip to content

Commit 2987e7f

Browse files
refactor: replace eval with ShadowRealm for safe expression evaluation
Remove dangerous eval() usage in the manual tool execution example and replace it with ShadowRealm API for secure, isolated JavaScript execution. ShadowRealm provides a separate realm with its own global object, preventing access to the host environment's APIs (no DOM, no Node.js APIs, no fetch, etc.), making it safe for evaluating untrusted expressions. Includes documentation link to TC39 proposal for contextual education. Co-Authored-By: Tom Aylott <thomas.42@gmail.com>
1 parent b458181 commit 2987e7f

File tree

1 file changed

+30
-3
lines changed

1 file changed

+30
-3
lines changed

examples/tools-example.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,34 @@ async function generatorToolExample() {
163163
const _message = await response.getMessage();
164164
}
165165

166+
/**
167+
* Safely evaluate a math expression using ShadowRealm
168+
*
169+
* ShadowRealm provides a secure, isolated JavaScript execution environment
170+
* 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.
172+
*
173+
* Browser support: Chrome 124+, Edge 124+, Firefox 128+, Safari 18+
174+
* Node.js support: Available behind --experimental-shadow-realm flag (v19+)
175+
* See: https://tc39.es/proposal-shadowrealm/
176+
*/
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.)
181+
const realm = new ShadowRealm();
182+
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})`);
186+
187+
if (typeof result !== 'number' || !Number.isFinite(result)) {
188+
throw new Error('Expression did not evaluate to a finite number');
189+
}
190+
191+
return result;
192+
}
193+
166194
/**
167195
* Example 3: Manual Tool Execution
168196
* Define a tool without execute function for manual handling
@@ -203,10 +231,9 @@ async function manualToolExample() {
203231
}
204232
).expression;
205233

206-
// In a real app, you would safely evaluate this
207-
// For demo purposes only - don't use eval in production!
234+
// Safely evaluate the math expression using ShadowRealm
208235
try {
209-
const _result = eval(expression);
236+
const _result = await safeEvaluateMath(expression);
210237
} catch (_error) {}
211238
}
212239
}

0 commit comments

Comments
 (0)