A sandbox meant to hold untrusted code in Prefab UI started with full read, write and network rights on the host. It stayed that way from March until late October. JFrog published the details on November 1.
What Happened?
Prefab UI is a PrefectHQ package that builds interfaces for FastMCP, installed with its apps option. Its Generative UI sandbox runs caller code through Pyodide inside a Deno subprocess. From version 0.14.0 through 0.20.2, that subprocess started with unrestricted read, write and network permissions, and the Deno API stayed reachable from the Python inside.
JFrog’s proof of concept, tracked as CVE-2026-120338, read a host file and wrote a new one. It also planted a .pth file in the server virtualenv, which the next Python process there ran. Version 0.21.0, released October 26, revokes those permissions before generated code runs.
What’s the Impact?
Exposure is narrow. Generative UI has to be switched on, Deno has to be installed, and untrusted callers have to reach the server. When all three are true, caller code reads and writes as the server’s user. JFrog scored it 10.0 out of 10 without a login, 9.9 with one.
Three things have to be true at once.
A CVSS score of 10.0 describes the worst case, not your case. Prefab UI’s sandbox escape only reaches a host where all three conditions below line up.
no auth
authenticated
at time of check
Not listed in CISA’s KEV catalog. Narrow exposure, maximum blast radius where it applies.
What a Caller Could Actually Do
Reading comes first. Config files, tokens, keys, anything on disk the service account can open.
Writing is the part that lasts. A .pth file dropped into site-packages runs on every interpreter start, so the next pip command or service restart executes whatever the caller left behind. That survives the patch.
Nobody is reporting attacks. The flaw is absent from CISA’s KEV catalog, and EPSS, which estimates the chance a flaw gets attacked in the next 30 days, put it at 0.77% when we checked.
The Scanner Gap
The entry in GitHub’s advisory database carries no package name and no version range, as of November 3. GitHub marks it unreviewed and says Dependabot alerts are unsupported for it. Anything reading that feed has nothing to match against. The CVE record itself does carry the package and the version range, so what your tooling tells you depends on which source it reads.
The dependency floor does not help either. FastMCP’s apps option accepts prefab-ui 0.18.0 or later with no upper bound, so a fresh install pulls the fixed build while an existing lock file keeps a vulnerable one.
How to Avoid This
- Check the installed prefab-ui version. The FastMCP version will not tell you
- Upgrade to 0.21.0 or later
- Search the virtualenv for unexpected .pth files before running pip
- Switch off Generative UI on any server untrusted callers can reach
- Rotate secrets readable by the server’s OS user
What to look for on a Prefab UI host
Proof of concept artifacts
| Indicator | What it means |
|---|---|
| /etc/passwd | Read target in the published proof of concept. A sandboxed payload reading it is the demonstrated file read. |
| /tmp/prefab-ui-sandbox-proof.txt | Write target in the published proof of concept. Its presence means someone ran the public payload against the host. |
| *.pth in site-packages | Persistence. A line starting with import runs on every interpreter start unless -S is passed. Check before running pip. |
Behavioral indicators
| Signal | Why it matters |
|---|---|
| generate_prefab_ui | The tool that reaches the sandbox. A call whose code references Deno or imports js is an incident, not a false positive. |
| Deno launched with –allow-read –allow-write –allow-net | Unscoped permissions. This is the vulnerable launcher behavior on 0.14.0 through 0.20.2. |
| Deno permission errors | On 0.21.0 and later the public payloads fail this way. Errors here mean someone tried. |
| Outbound from sandbox to anything but cdn.jsdelivr.net:443 | 0.21.0 scopes bootstrap network access to that host only. Other destinations warrant a look. |
Version and config checks
| Where | What to confirm |
|---|---|
| prefab-ui installed version | Affected: 0.14.0 up to and including 0.20.2. Fixed: 0.21.0 and later. Check the package itself, not the FastMCP version. |
| fastmcp-slim 4.1.6 apps extra | Accepts prefab-ui>=0.18.0 with no upper bound, so a lock file can still pin a vulnerable build. |
| *.lock, requirements*.txt | Where a vulnerable prefab-ui pin hides. |
| Deno on PATH | No Deno, no sandbox, no exposure through this path. |
Hunt commands
# 1. Is Generative UI wired up anywhere in this codebase? grep -rnE "GenerativeUI|prefab_ui\.sandbox" --include="*.py" . # 2. What version is actually pinned? grep -rn -A1 "prefab-ui" --include="*.lock" --include="requirements*.txt" . # 3. Run this BEFORE any pip command. pip starts Python, # and a planted .pth file runs on startup. find /path/to/venv -name '*.pth' -ls # 4. Any .pth line starting with import is executable code. grep -n '^import' /path/to/venv/lib/python*/site-packages/*.pth # 5. Proof of concept write target. ls -la /tmp/prefab-ui-sandbox-proof.txt 2>/dev/null
Sources: JFrog Security Research advisory JFSA-2026-001699278, the CVE record for CVE-2026-120338, and PyPI package metadata. Verified November 3, 2026.
Also Worth a Look
JFrog published three Beta9 container escape advisories on November 1, each scored 9.9. Two are fixed in worker 0.1.756. The third, a gateway side volume ownership check, also needs gateway 0.1.776.
Start With the Version Number on the Host
Secure.com relies on your scanners to see the prefab-ui Python package. As of 3 November, we found no package version advisory for CVE-2026-120338 that a scanner could match, so check the installed prefab-ui version directly.
When your vulnerability scanner reports CVE-2026-120338 on a host or a container image, Secure.com shows it on that asset with its KEV status, EPSS score and exploit evidence.