CVE-2026-120338: Patch the Prefab UI Sandbox Escape

Generated UI sandbox isolated from host files and network access after the CVE-2026-120338 patch

CVE-2026-120338 breaks a boundary that AI application teams may assume is safe: Prefab UI’s Generative UI sandbox could let caller-supplied Python reach Deno’s host filesystem and network permissions. The issue affects prefab-ui 0.14.0 through 0.20.2 and is fixed in 0.21.0. Teams operating FastMCP or other services that enable Generative UI should inventory deployments, upgrade, review exposed hosts, and avoid treating WebAssembly alone as a security boundary.

Defender summary: The vulnerable feature is opt-in and requires Deno. Exposure is highest when an unauthenticated or broadly authorized client can call the Generative UI tool. Upgrade prefab-ui to 0.21.0 or later. Until then, remove the provider from reachable services rather than relying on the old sandbox.

What was disclosed

JFrog Security Research published CVE-2026-120338 on November 1, 2026. The project had already released prefab-ui 0.21.0 on October 26 with the relevant sandbox changes. The affected component runs generated Python inside Pyodide, a Python runtime compiled to WebAssembly, while a Deno subprocess provides the surrounding JavaScript environment.

The security failure was not a generic WebAssembly escape. The runner started Deno with filesystem read, filesystem write, and network permissions, then left the Deno API reachable through the JavaScript global object. Pyodide’s bridge to JavaScript made those host capabilities accessible to caller-supplied Python. In other words, the inner code did not need to break WebAssembly memory isolation; it could use permissions intentionally granted to the outer runtime.

Affected scope and exposure conditions

ConditionWhy it mattersDefender conclusion
prefab-ui 0.14.0 to 0.20.2Contains the vulnerable permission modelUpgrade is required
Generative UI provider enabledRegisters the code-generating execution pathActive exposure condition
Deno installed and availableThe sandbox subprocess depends on DenoActive exposure condition
Tool reachable without authenticationAny reachable client may be able to submit codeHighest-priority case
Tool requires authenticationAuthorized tool callers may still cross the boundaryPatch; authentication is not a complete fix
prefab-ui 0.21.0 or laterRevokes Deno read, write, and network permissions before accepting generated codeFixed version floor

A vulnerable package in a lockfile is not automatically a remotely exploitable service. The Generative UI provider must be enabled, Deno must be available, and a caller must be able to reach the relevant tool. Those prerequisites are useful for prioritization, but they should not be used to postpone the upgrade. Configuration changes, new providers, or future deployments can activate dormant risk.

Why this matters for AI and MCP architectures

Generative interfaces turn model output into executable application behavior. That can be useful, but it also combines two difficult trust problems: an upstream model or client supplies code, and a runtime must enforce strict limits on what that code can see or change. The name “sandbox” is not proof that the boundary is complete.

  • Capability inheritance: code inside a restricted runtime may still reach powerful APIs exposed by the host language bridge.
  • Tool authorization: an authenticated MCP client can still be untrusted for a particular high-impact tool.
  • Persistence opportunity: host filesystem write access can alter application environments or startup paths beyond the current request.
  • Secret exposure: host files and environment-adjacent resources may contain tokens, configuration, or service credentials.
  • Egress: network permission can turn local read access into data exfiltration if outbound traffic is unrestricted.

This is a concrete example of a broader AI-agent lesson: authorize generated actions according to their effects, not according to whether they arrive through a model, an MCP client, or a UI provider. The same control should apply to human-authored and model-authored code.

Immediate response plan

1. Find package and runtime exposure

Search Python lockfiles, container manifests, SBOMs, build logs, and deployed environments for prefab-ui. Record the exact installed version rather than the declared range alone. Then identify services that register FastMCP’s Generative UI provider or otherwise instantiate Prefab’s Pyodide sandbox. Confirm whether Deno is installed in the same image or host and whether the tool is reachable from untrusted networks or clients.

python3 -m pip show prefab-ui
python3 -m pip freeze | grep -i '^prefab-ui=='
command -v deno && deno --version
grep -R --line-number --exclude-dir=.git 'GenerativeUI' .

Run these commands only in repositories and hosts you are authorized to inspect. A package manager may report a fixed library while a running container still uses an older image, so compare deployed image digests with the rebuilt artifact.

2. Contain high-risk services

If an affected service is reachable, remove the Generative UI provider or restrict the service to a trusted administration network until the upgrade is deployed. Do not assume authentication is sufficient: any principal allowed to call the vulnerable tool may be able to reach capabilities outside the intended sandbox. Restrict egress and protect application directories with least-privilege filesystem ownership as defense in depth.

3. Upgrade and rebuild

Upgrade to prefab-ui 0.21.0 or later, regenerate the lockfile, rebuild container images without cache where appropriate, and redeploy using a new immutable digest. Version 0.21.0 starts the Deno process with --no-prompt, limits bootstrap network access, and revokes filesystem read, filesystem write, and network permissions before generated code is accepted.

python3 -m pip install --upgrade 'prefab-ui>=0.21.0'
python3 -m pip show prefab-ui
python3 -m pip check

4. Investigate before declaring closure

The public sources describe the vulnerability and a proof of concept, but they do not establish widespread exploitation. Do not label every affected host compromised. For exposed deployments, review MCP tool-call logs, authentication records, process creation, Deno activity, outbound connections, and changes to the application virtual environment. Compare files against a trusted build and rotate credentials if evidence shows that generated code could have read them.

Detection and forensic priorities

  • Unexpected calls to the Generative UI tool, especially from new clients, anonymous sessions, or unusual source networks.
  • Deno subprocesses launched outside normal deployment or request patterns.
  • Writes under the Python virtual environment, particularly site-packages, startup hooks, or dependency metadata after deployment.
  • Reads of configuration, credential, SSH, cloud, or service-account paths by the application identity.
  • Outbound DNS and network connections from the sandbox process to destinations not required for approved bootstrap behavior.
  • Drift between a running container filesystem and its signed or trusted image.

Preserve logs and a copy of the affected image before destructive cleanup when an incident is suspected. Local application logs may be incomplete, so correlate reverse-proxy, identity-provider, container-runtime, DNS, and network telemetry.

Hands-on lab: offline Prefab UI inventory triage

This lab classifies synthetic inventory. It never imports prefab-ui, starts Deno, exposes an MCP endpoint, or executes generated code. Use it to test triage logic before adapting the CSV fields to an approved SBOM or configuration export.

Prerequisites

  • Python 3.9 or newer
  • A disposable directory with no secrets
  • No network access required
service,prefab_ui_version,generative_ui_enabled,deno_installed,network_exposed,owner
design-agent,0.20.2,yes,yes,yes,ai-platform
internal-prototype,0.18.0,no,yes,no,developer-tools
ui-gateway,0.21.0,yes,yes,yes,ai-platform
legacy-worker,0.13.2,yes,yes,no,data-platform
unknown-build,custom-main,yes,yes,yes,research
import csv, re, sys

def parse_version(value):
    match = re.fullmatch(r"(\d+)\.(\d+)\.(\d+)", value.strip())
    return tuple(map(int, match.groups())) if match else None

def classify(row):
    version = parse_version(row["prefab_ui_version"])
    enabled = row["generative_ui_enabled"].lower() == "yes"
    deno = row["deno_installed"].lower() == "yes"
    exposed = row["network_exposed"].lower() == "yes"
    if version is None:
        return "REVIEW", "unrecognized version"
    if version < (0, 14, 0):
        return "OUT_OF_RANGE", "version predates affected range"
    if version >= (0, 21, 0):
        return "CURRENT", "fixed version or later"
    if not enabled or not deno:
        return "DORMANT", "affected package present; vulnerable path not active"
    if exposed:
        return "URGENT", "affected path active and network exposed"
    return "PATCH", "affected path active"

with open(sys.argv[1], newline="", encoding="utf-8") as handle:
    print("service,version,disposition,reason")
    for row in csv.DictReader(handle):
        disposition, reason = classify(row)
        print(f'{row["service"]},{row["prefab_ui_version"]},{disposition},{reason}')

Save the files as prefab_inventory.csv and audit_prefab_ui.py, then run:

python3 audit_prefab_ui.py prefab_inventory.csv

Expected output:

service,version,disposition,reason
design-agent,0.20.2,URGENT,affected path active and network exposed
internal-prototype,0.18.0,DORMANT,affected package present; vulnerable path not active
ui-gateway,0.21.0,CURRENT,fixed version or later
legacy-worker,0.13.2,OUT_OF_RANGE,version predates affected range
unknown-build,custom-main,REVIEW,unrecognized version

Troubleshooting and cleanup

If Python cannot find the CSV, run pwd and ls -l to confirm both files are in the working directory. Keep REVIEW for development builds and nonstandard version strings; do not guess their security state. Delete the disposable directory after the exercise. The script was executed against the sample data, but it has not been tested against a production SBOM export.

Hardening beyond the patch

  • Require authentication and explicit per-tool authorization for every MCP endpoint.
  • Separate generated-code execution from the application control plane and sensitive secrets.
  • Use a read-only root filesystem, minimal writable mounts, an unprivileged identity, and a restrictive seccomp or sandbox profile.
  • Default-deny egress and permit only documented bootstrap destinations.
  • Log tool identity, caller identity, request correlation, process creation, and policy denials.
  • Test the negative security contract: generated code should fail when it requests host files, network access, environment secrets, or persistence.

For broader architecture controls, see Microsoft’s Five AI Agent Risk Classes. The filesystem-isolation lessons also connect directly to SharedRoot: The Real Risk of Shared Filesystem Access in Containerized AI Workloads.

Conclusion

CVE-2026-120338 is a reminder that an AI sandbox is only as strong as every capability exposed across its language and runtime bridges. Prefab UI 0.21.0 closes the documented Deno permission path, but operators should also narrow tool authorization, filesystem access, and network egress. Inventory first, prioritize reachable Generative UI services, upgrade through an immutable rebuild, and investigate exposed hosts before closing the issue.

Primary sources

Similar Posts