ruvnet/ruflo · error · Error
browser/eval: script contains disallowed pattern: ${pattern.
Error message
browser/eval: script contains disallowed pattern: ${pattern.source} What it means
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.
Source
Thrown at v3/@claude-flow/browser/src/mcp-tools/browser-tools.ts:677
},
},
required: ['script'],
},
handler: async (input) => {
const script = input.script as string;
// Validate script length
if (!script || script.length === 0) {
throw new Error('browser/eval: script must not be empty');
}
if (script.length > MAX_EVAL_SCRIPT_LENGTH) {
throw new Error(`browser/eval: script exceeds maximum length of ${MAX_EVAL_SCRIPT_LENGTH} characters`);
}
// Check for dangerous patterns
for (const pattern of DANGEROUS_EVAL_PATTERNS) {
if (pattern.test(script)) {
throw new Error(`browser/eval: script contains disallowed pattern: ${pattern.source}`);
}
}
// Audit log
console.info(`[browser/eval] Executing script (${script.length} chars) in session ${input.session || 'default'}`);
const adapter = getAdapter(input.session as string);
return adapter.eval({ script });
},
},
];
// ============================================================================
// Storage Tools
// ============================================================================
const storageTools: MCPTool[] = [
{View on GitHub (pinned to 6b01dc5a68)
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.
Example fix
// before
await evalTool.handler({ script: 'globalThis.myVal = 42;' }); // throws 64 (globalThis)
// after
await evalTool.handler({ script: 'window.myVal = 42;' }); Defensive patterns
Strategy: validation
Validate before calling
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*\(/];
function isSafeScript(script) {
return typeof script === 'string' && !BLOCKED.some(p => p.test(script));
} Type guard
null
Try / catch
null
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: LLM-generated scripts that reference Node globals; reusing Node-targeted code in the page; bundlers that emit require() calls; accessing window via globalThis.
Related errors
- browser/eval: script must not be empty
- browser/eval: script exceeds maximum length of ${MAX_EVAL_SC
- Issue not found: ${input.issueId}
- Issue ${input.issueId} is already claimed by ${issue.claimed
- Issue ${input.issueId} is not claimed by ${input.claimantId}
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/5da204444322c0e5.
Report an issue: GitHub.