{"record":{"id":"5da204444322c0e5","repo":"ruvnet/ruflo","slug":"browser-eval-script-contains-disallowed-pattern","errorCode":null,"errorMessage":"browser/eval: script contains disallowed pattern: ${pattern.source}","messagePattern":"browser/eval: script contains disallowed pattern: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/browser/src/mcp-tools/browser-tools.ts","lineNumber":677,"sourceCode":"        },\n      },\n      required: ['script'],\n    },\n    handler: async (input) => {\n      const script = input.script as string;\n\n      // Validate script length\n      if (!script || script.length === 0) {\n        throw new Error('browser/eval: script must not be empty');\n      }\n      if (script.length > MAX_EVAL_SCRIPT_LENGTH) {\n        throw new Error(`browser/eval: script exceeds maximum length of ${MAX_EVAL_SCRIPT_LENGTH} characters`);\n      }\n\n      // Check for dangerous patterns\n      for (const pattern of DANGEROUS_EVAL_PATTERNS) {\n        if (pattern.test(script)) {\n          throw new Error(`browser/eval: script contains disallowed pattern: ${pattern.source}`);\n        }\n      }\n\n      // Audit log\n      console.info(`[browser/eval] Executing script (${script.length} chars) in session ${input.session || 'default'}`);\n\n      const adapter = getAdapter(input.session as string);\n      return adapter.eval({ script });\n    },\n  },\n];\n\n// ============================================================================\n// Storage Tools\n// ============================================================================\n\nconst storageTools: MCPTool[] = [\n  {","sourceCodeStart":659,"sourceCodeEnd":695,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/browser/src/mcp-tools/browser-tools.ts#L659-L695","documentation":"Thrown by browser/eval when the script matches any regex in DANGEROUS_EVAL_PATTERNS. The blocklist includes: process, require, __dirname, __filename, child_process, global. (with dot), globalThis, Function(, .constructor, Reflect, import(, and eval(. The thrown message echoes the offending pattern.source so you can see which rule fired. This is a defense-in-depth layer, explicitly noted as bypassable — the browser sandbox is the real boundary.","triggerScenarios":"Any eval script that contains one of the blocked substrings as a literal or via a regex match, including innocent uses like the word 'process' in a comment, a webpack require shim, or accessing globalThis for a polyfill.","commonSituations":"LLM-generated scripts that reference Node globals; reusing Node-targeted code in the page; bundlers that emit require() calls; accessing window via globalThis.","solutions":["Rewrite the script to avoid the blocked token (e.g., use 'window' instead of 'globalThis', avoid 'process' entirely).","Strip Node-specific code before sending — the eval runs in the page context, not Node.","If a blocked token is unavoidable and the script is trusted, move the logic into a page-loaded module invoked by a thin eval wrapper."],"exampleFix":"// before\nawait evalTool.handler({ script: 'globalThis.myVal = 42;' }); // throws 64 (globalThis)\n\n// after\nawait evalTool.handler({ script: 'window.myVal = 42;' });","handlingStrategy":"validation","validationCode":"const BLOCKED = [/\\bprocess\\b/, /\\brequire\\b/, /\\b__dirname\\b/, /\\b__filename\\b/, /\\bchild_process\\b/, /\\bglobal\\b\\s\\./, /\\bglobalThis\\b/, /\\bFunction\\s*\\(/, /\\.constructor\\b/, /\\bReflect\\b/, /\\bimport\\s*\\(/, /\\beval\\s*\\(/];\nfunction isSafeScript(script) {\n  return typeof script === 'string' && !BLOCKED.some(p => p.test(script));\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Author eval scripts for the page context — never reference Node globals.","Run your own blocklist check before sending so the failure surfaces at the caller.","Remember the blocklist is defense-in-depth, not a sandbox; the browser sandbox is the real boundary."],"tags":["mcp","browser-eval","security","blocklist","typescript"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}