@@ -34,6 +34,59 @@ const TAG_PATTERN = createReferencePattern()
3434const E2B_JS_WRAPPER_LINES = 3
3535const E2B_PYTHON_WRAPPER_LINES = 1
3636
37+ /** Matches valid JS identifier names (letters, digits, underscore; no leading digit). */
38+ const SAFE_IDENTIFIER = / ^ [ a - z A - Z _ ] [ a - z A - Z 0 - 9 _ ] * $ /
39+
40+ /** ES2023 reserved words — using these as `const` variable names produces a SyntaxError. */
41+ const JS_RESERVED_WORDS = new Set ( [
42+ 'break' ,
43+ 'case' ,
44+ 'catch' ,
45+ 'class' ,
46+ 'const' ,
47+ 'continue' ,
48+ 'debugger' ,
49+ 'default' ,
50+ 'delete' ,
51+ 'do' ,
52+ 'else' ,
53+ 'export' ,
54+ 'extends' ,
55+ 'false' ,
56+ 'finally' ,
57+ 'for' ,
58+ 'function' ,
59+ 'if' ,
60+ 'import' ,
61+ 'in' ,
62+ 'instanceof' ,
63+ 'let' ,
64+ 'new' ,
65+ 'null' ,
66+ 'return' ,
67+ 'static' ,
68+ 'super' ,
69+ 'switch' ,
70+ 'this' ,
71+ 'throw' ,
72+ 'true' ,
73+ 'try' ,
74+ 'typeof' ,
75+ 'var' ,
76+ 'void' ,
77+ 'while' ,
78+ 'with' ,
79+ 'yield' ,
80+ 'enum' ,
81+ 'await' ,
82+ 'implements' ,
83+ 'interface' ,
84+ 'package' ,
85+ 'private' ,
86+ 'protected' ,
87+ 'public' ,
88+ ] )
89+
3790type TypeScriptModule = typeof import ( 'typescript' )
3891
3992let typescriptModulePromise : Promise < TypeScriptModule > | null = null
@@ -1089,18 +1142,24 @@ export const POST = withRouteHandler(async (req: NextRequest) => {
10891142
10901143 const executionMethod = 'isolated-vm'
10911144
1145+ const isSafeParamKey = ( key : string ) => SAFE_IDENTIFIER . test ( key ) && ! JS_RESERVED_WORDS . has ( key )
1146+
10921147 const wrapperLines = [ '(async () => {' , ' try {' ]
10931148 if ( isCustomTool ) {
10941149 Object . keys ( executionParams ) . forEach ( ( key ) => {
1095- wrapperLines . push ( ` const ${ key } = params.${ key } ;` )
1150+ if ( isSafeParamKey ( key ) ) {
1151+ wrapperLines . push ( ` const ${ key } = params.${ key } ;` )
1152+ } else {
1153+ logger . warn ( 'Skipping param key — not a safe JS identifier' , { key, requestId } )
1154+ }
10961155 } )
10971156 }
10981157 userCodeStartLine = wrapperLines . length + 1
10991158
11001159 let codeToExecute = resolvedCode
11011160 let prependedLineCount = 0
11021161 if ( isCustomTool ) {
1103- const paramKeys = Object . keys ( executionParams )
1162+ const paramKeys = Object . keys ( executionParams ) . filter ( isSafeParamKey )
11041163 const paramDestructuring = paramKeys . map ( ( key ) => `const ${ key } = params.${ key } ;` ) . join ( '\n' )
11051164 codeToExecute = `${ paramDestructuring } \n${ resolvedCode } `
11061165 prependedLineCount = paramKeys . length
0 commit comments