{"record":{"id":"f3a199710b26af99","repo":"microsoft/playwright","slug":"access-to-file-protocol-is-blocked-attempted-u","errorCode":null,"errorMessage":"Access to \"file:\" protocol is blocked. Attempted URL: \"${url}\"","messagePattern":"Access to \"file:\" protocol is blocked\\. Attempted URL: \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/tools/backend/context.ts","lineNumber":349,"sourceCode":"    await this._setupRequestInterception(browserContext);\n\n    for (const initScript of this.config.browser?.initScript || [])\n      this._disposables.push(await browserContext.addInitScript({ path: path.resolve(this.options.cwd, initScript) }));\n\n    for (const page of browserContext.pages())\n      this._onPageCreated(page);\n    this._disposables.push(eventsHelper.addEventListener(browserContext, 'page', page => this._onPageCreated(page)));\n\n    return browserContext;\n  }\n\n  checkUrlAllowed(url: string) {\n    if (this.config.allowUnrestrictedFileAccess)\n      return;\n    if (!URL.canParse(url))\n      return;\n    if (new URL(url).protocol === 'file:')\n      throw new Error(`Access to \"file:\" protocol is blocked. Attempted URL: \"${url}\"`);\n  }\n\n  lookupSecret(secretName: string): { value: string, code: string, isSecret: boolean } {\n    if (!this.config.secrets?.[secretName])\n      return { value: secretName, code: escapeWithQuotes(secretName, '\\''), isSecret: false };\n    const codegen = this.config.codegen ?? 'typescript';\n    return {\n      value: this.config.secrets[secretName]!,\n      code: secretCode(codegen === 'none' ? 'typescript' : codegen, secretName),\n      isSecret: true,\n    };\n  }\n\n  redactSecrets(text: string): string {\n    for (const [secretName, secretValue] of Object.entries(this.config.secrets ?? {})) {\n      if (!secretValue)\n        continue;\n      text = text.replaceAll(secretValue, `<secret>${secretName}</secret>`);","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/tools/backend/context.ts#L331-L367","documentation":"Thrown by Context.checkUrlAllowed when a navigation/request targets a file: URL and the config flag allowUnrestrictedFileAccess is not set. The check is skipped entirely (returns early) when URL.canParse fails, but a well-formed file:// URL with the flag disabled is blocked to keep LLM-driven navigation from touching the local filesystem.","triggerScenarios":"Any navigation, goto, or request-initiating MCP tool called with a file:// URL while ContextConfig.allowUnrestrictedFileAccess is unset/false.","commonSituations":"MCP agent opening a locally generated HTML report; a test harness that tries to view file:// fixtures through the MCP browser; default config which ships with file access blocked for safety.","solutions":["Serve the file over http(s) (e.g. a local static server) and navigate to that URL instead.","If local file access is intended and the trust boundary allows it, enable allowUnrestrictedFileAccess in the MCP/browser config.","Rewrite the target so checkUrlAllowed sees an http(s) URL."],"exampleFix":"// before\nawait page.goto('file:///home/user/report.html'); // throws via checkUrlAllowed\n\n// after (option A - serve)\nawait page.goto('http://localhost:8080/report.html');\n\n// after (option B - allow)\n// context config: { allowUnrestrictedFileAccess: true }","handlingStrategy":"validation","validationCode":"function isAllowedUrl(url: string, allowFile = false): boolean {\n  if (!URL.canParse(url)) return true; // mirrors checkUrlAllowed early-out\n  const proto = new URL(url).protocol;\n  if (proto === 'file:') return allowFile;\n  return true;\n}\n\nif (!isAllowedUrl(target, !!config.allowUnrestrictedFileAccess)) {\n  throw new Error(`Refusing file: URL: ${target}`);\n}","typeGuard":"function isFileProtocol(url: string): boolean {\n  return URL.canParse(url) && new URL(url).protocol === 'file:';\n}","tryCatchPattern":"try {\n  await page.goto(target);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Access to \"file:\" protocol is blocked')) {\n    // serve locally instead, or re-run with allowUnrestrictedFileAccess after user consent\n  } else throw e;\n}","preventionTips":["Never pass file:// URLs to navigation tools unless the config explicitly allows it.","Wrap local files in an http server when driving the browser via MCP.","Centralize URL validation upstream so agents cannot reach checkUrlAllowed with a file URL."],"tags":["security","navigation","file-protocol","config-gate"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}