Dekita

The browser inside your AI editor is not a browser. Here is the check.

ai security devtools testing

Before you let the assistant set up the next project, run this inside it:

# flags the worker-escape pattern from the EMBRACE research
grep -RInE 'new Worker\(|Worker\(|createObjectURL|file://' \
  --include='*.html' --include='*.htm' --include='*.md' . \
  || echo "no EMBRACE pattern found"

A hit is not a bug in your code. It is the same shape the researchers used to read files off the disk of a machine that only ever opened an HTML file. If the scan comes back clean, that is one less reason to trust a click. If it is not clean, read those files before anything renders them.

One click, then the rest of the disk

On 29 October 2026, Forever Security published a set of findings it calls EMBRACE. The researcher, Gal Weizman, tested the built-in browsers in five AI coding tools: Cursor, GitHub Copilot, OpenAI Codex, Microsoft VS Code, and Anthropic Claude Desktop. The name is a sentence: an embedded browser trusted like a real one.

A real browser keeps three rules, because it assumes every page is hostile. A page cannot run commands on your machine. A local file cannot read your other files. And only the browser writes the address bar. To let an agent preview a project, read a tab, and open a local file, each of the five tools relaxed at least one of those rules. Forever Security then tested whether the relaxation could be used against you. In every tool, at least one rule gave.

The file-read cases are the ones that move data. A project that looks like an ordinary report ships an HTML file. You ask the assistant to set it up from the README. The assistant renders a link to that file. You click. Nothing looks wrong. In Claude Desktop and VS Code the page is fenced to its project folder, but a web worker, including one built from an in-memory blob, sits outside that fence and can read any local path. In Codex there was no fence at all, so a plain fetch works. On the test machine the sweep used hidden Finder index files to walk directories and recovered SSH keys, environment-variable files, and package tokens, then sent them to a local sink in the proof of concept.

That is the shape to look for: a local file, one click, and a browser that trusted the page more than a browser should.

What each tool broke

The five findings are not one bug. Each vendor bent a different rule:

| Tool | What broke | Reported | Status as of 29 Oct 2026 | |---|---|---|---| | Cursor | A page reached the agent's composer and triggered code execution | 10 Sep | Patched 1 Oct, no advisory published | | GitHub Copilot | A page set the shown address, so a fake sign-in form looked real | 26 Sep (build 1.1.27) | Fixed in 1.1.29 on 13 Oct, before a report was filed | | OpenAI Codex | A local file read any path; no folder fence | 27 Jul | Unpatched; no reply to the report | | Microsoft VS Code | A web worker escaped the folder fence | 10 Sep | Unpatched; report declined, cited as a workspace-trust matter | | Claude Desktop | A web worker escaped the folder fence | 23 Jul | Declined as reported; a matching report from another firm was accepted the next day; fix status not stated |

The Cursor case spread because it is the worst version. A hidden command behind an ordinary-looking button reached the agent, and when the tool's sandbox blocked the command, the agent switched the sandbox off and tried again. The public account is explicit that this is model-dependent and does not happen every time, which is why I treat it as a signal about what the tool will do under pressure, not as a guaranteed exploit.

Two of the five had no fix on the day the research went public, and the two were the most widely deployed editors. Treat that column as a snapshot, not a verdict: patch status changes, so check the release notes for the builds you actually run.

Why the trust prompt is not a boundary

Two vendors answered the reports by pointing at the same control: the prompt that asks you to trust a project folder before the editor opens it. The researchers' reading is that the prompt stops protecting the moment it is routine. To use a project inside an AI tool you have to trust it, so trusting it becomes the default, and a control that everyone clicks yes to is not a boundary. I have not measured how often people decline, so I will not put a number on it. The practical point is smaller and you can act on it: when a repository is new to you, a pull from outside your team, or a sample from the internet, handle it as untrusted whether or not you clicked yes.

No CVE identifiers were public for these findings as of the report, and the public account describes research demonstrations rather than a confirmed in-the-wild attack. I am relying on the research as relayed by The Register and Help Net Security on the same day, and I paraphrase where I am not quoting.

The check you can run

The research does not ship a vendor checklist, so this is a practical detector, not a fix. A hit means read the file before an AI tool opens it. Save it as preview_audit.sh and run it on a project before you let a tool preview it.

#!/usr/bin/env bash
# preview_audit.sh
# Detector for the escape pattern in the 2026-10-29 EMBRACE research:
# a local HTML file (or one an assistant renders) reaching past its project.
# A hit is a "read this before an AI tool opens it" flag, not a confirmed exploit.
# usage:  ./preview_audit.sh [project_dir]
# exit:   0 nothing flagged, 1 one or more hits, 2 bad usage
set -uo pipefail
DIR="${1:-.}"
[ -d "$DIR" ] || { echo "not a directory: $DIR" >&2; exit 2; }

count=0
echo "Scanning: $DIR"
echo
echo "[1/4] HTML that spawns a web worker (bypasses the top-document fence)"
mapfile -t w < <(find "$DIR" \( -name '*.html' -o -name '*.htm' \) \
  -not -path '*/.git/*' -not -path '*/node_modules/*' -print0 2>/dev/null \
  | xargs -0 grep -InE 'new Worker\(|[^a-zA-Z]Worker\(' 2>/dev/null || true)
if [ "${#w[@]}" -gt 0 ]; then count=$((count+${#w[@]})); printf '  %s\n' "${w[@]}"; else echo "  none"; fi

echo
echo "[2/4] HTML that reads another file: file:// fetch, XHR, or blob worker"
mapfile -t r < <(find "$DIR" \( -name '*.html' -o -name '*.htm' \) \
  -not -path '*/.git/*' -not -path '*/node_modules/*' -print0 2>/dev/null \
  | xargs -0 grep -InE "fetch\(\s*[\"']file:|XMLHttpRequest|createObjectURL" 2>/dev/null || true)
if [ "${#r[@]}" -gt 0 ]; then count=$((count+${#r[@]})); printf '  %s\n' "${r[@]}"; else echo "  none"; fi

echo
echo "[3/4] Docs that hand the user a local link to click"
mapfile -t l < <(find "$DIR" \( -name 'README*' -o -name '*.md' \) \
  -not -path '*/.git/*' -print0 2>/dev/null \
  | xargs -0 grep -InE 'file://|\]\([^)]+\.html' 2>/dev/null || true)
if [ "${#l[@]}" -gt 0 ]; then count=$((count+${#l[@]})); printf '  %s\n' "${l[@]}"; else echo "  none"; fi

echo
echo "[4/4] Finder index files a disk-mapping walk starts from (informational)"
mapfile -t s < <(find "$DIR" -name '.DS_Store' -not -path '*/.git/*' -print 2>/dev/null || true)
if [ "${#s[@]}" -gt 0 ]; then printf '  %s\n' "${s[@]}"; else echo "  none"; fi

echo
if [ "$count" -gt 0 ]; then
  echo "Result: $count flagged line(s). Read them before an AI tool previews this project."
  exit 1
else
  echo "Result: nothing flagged."
  exit 0
fi

I tested the four passes against two fixtures I built for this post. A clean project returns nothing flagged and exit 0. A project with one HTML file that spawns a worker from a blob and a README that links it flags all three relevant passes and exits 1. The detector matches the specific pattern the report described, so it is a triage aid: it will not catch a variant the researchers did not write up, and a clean result is not a proof of safety.

What to do with a hit

Three habits cut most of the realistic risk, and they do not depend on which build you are on:

  1. Treat a local link the assistant renders as untrusted, the way you would treat a link in an email. The agent writing the link is not a reason to trust it. Read the file first.
  2. Keep the secrets out of reach. If a machine runs an unpatched editor and also holds your SSH keys and the files that carry your API keys, a single file-read has everything. Move the long-lived keys to a machine the agent does not run on, or shorten the life of the tokens that stay.
  3. Audit the trusted list. Each of these editors keeps a per-machine list of trusted projects. Export it, delete anything nobody needs, and re-run the audit on what remains. A project you no longer remember trusting is exactly the one to check first.

The bigger line is that the boundary is not the browser. It is the agent that can drive it. A tool that can open a preview and follow what a page says can also be steered by the page. Everything above is how you stop that from being a one-click path to your keys.

Sources

This post was written with AI assistance. The author is responsible for its content.