CVE-2026-120338 (GCVE-0-2026-120338)

Vulnerability from cvelistv5 – Published: 2026-11-01 15:24 – Updated: 2026-11-01 15:24
VLAI
Title
Prefab UI Pyodide sandbox escape to host RCE
Summary
Prefab UI's Generative UI sandbox runs caller-supplied Python inside Pyodide, Python compiled to WebAssembly, in a Deno subprocess. The feature is documented as isolation for untrusted code, including LLM-written UI. From prefab-ui 0.14.0 through 0.20.2 the launcher starts Deno with unrestricted --allow-read, --allow-write, and --allow-net, and the runner leaves the Deno API on the JavaScript global object. Pyodide's js module proxies that global, so the Python can call Deno.readTextFileSync and Deno.writeTextFileSync. A caller who can supply the code can read and write files as the server OS user, and can persist code execution by writing a .pth file into the server virtualenv's site-packages. The usual remote path is FastMCP's GenerativeUI provider, which registers the MCP tool generate_prefab_ui and forwards that tool's code argument into this sandbox. On a FastMCP server with no authentication configured, any client who can reach the server can call the tool. With authentication, any client allowed to call tools can. Generative UI is opt-in, and the host must have Deno installed. Confirmed on prefab-ui 0.20.2. Fixed in 0.21.0: after the runtime and Prefab sources load, the runner revokes Deno read, write, and network permission before it accepts code, the process is started with --no-prompt so a permission request cannot grant them again, and bootstrap network access is limited to cdn.jsdelivr.net. The fix is commit 030f074 (pull request 538).
CWE
  • CWE-693 - Protection Mechanism Failure
  • CWE-94 - Improper Control of Generation of Code ('Code Injection')
  • CWE-269 - Improper Privilege Management
Assigner
JFROG CNA under the mitre root
CNA scorecard B 76/100 over 66 records in the last 180 days details
Impacted products
Vendor Product Version CPE status
PrefectHQ prefab-ui Affected: 0.14.0 , < 0.21.0 (semver)
guessed Create a notification for this product.
Show details on NVD website

{
  "containers": {
    "cna": {
      "affected": [
        {
          "collectionURL": "https://pypi.org/project/prefab-ui/",
          "defaultStatus": "unaffected",
          "packageName": "prefab-ui",
          "product": "prefab-ui",
          "programFiles": [
            "src/prefab_ui/sandbox/_pyodide.py",
            "src/prefab_ui/sandbox/runner.js"
          ],
          "repo": "git://github.com/PrefectHQ/prefab",
          "vendor": "PrefectHQ",
          "versions": [
            {
              "lessThan": "0.21.0",
              "status": "affected",
              "version": "0.14.0",
              "versionType": "semver"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "Yuval Moravchick"
        },
        {
          "lang": "en",
          "type": "coordinator",
          "value": "JFrog Security Research"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "supportingMedia": [
            {
              "base64": false,
              "type": "text/html",
              "value": "\u003cp\u003ePrefab UI\u0027s Generative UI sandbox runs caller-supplied Python inside Pyodide, Python compiled to WebAssembly, in a Deno subprocess. The feature is documented as isolation for untrusted code, including LLM-written UI. From prefab-ui 0.14.0 through 0.20.2 the launcher starts Deno with unrestricted --allow-read, --allow-write, and --allow-net, and the runner leaves the Deno API on the JavaScript global object. Pyodide\u0027s js module proxies that global, so the Python can call Deno.readTextFileSync and Deno.writeTextFileSync. A caller who can supply the code can read and write files as the server OS user, and can persist code execution by writing a .pth file into the server virtualenv\u0027s site-packages. The usual remote path is FastMCP\u0027s GenerativeUI provider, which registers the MCP tool generate_prefab_ui and forwards that tool\u0027s code argument into this sandbox. On a FastMCP server with no authentication configured, any client who can reach the server can call the tool. With authentication, any client allowed to call tools can. Generative UI is opt-in, and the host must have Deno installed. Confirmed on prefab-ui 0.20.2. Fixed in 0.21.0: after the runtime and Prefab sources load, the runner revokes Deno read, write, and network permission before it accepts code, the process is started with --no-prompt so a permission request cannot grant them again, and bootstrap network access is limited to cdn.jsdelivr.net. The fix is commit 030f074 (pull request 538).\u003c/p\u003e"
            }
          ],
          "value": "Prefab UI\u0027s Generative UI sandbox runs caller-supplied Python inside Pyodide, Python compiled to WebAssembly, in a Deno subprocess. The feature is documented as isolation for untrusted code, including LLM-written UI. From prefab-ui 0.14.0 through 0.20.2 the launcher starts Deno with unrestricted --allow-read, --allow-write, and --allow-net, and the runner leaves the Deno API on the JavaScript global object. Pyodide\u0027s js module proxies that global, so the Python can call Deno.readTextFileSync and Deno.writeTextFileSync. A caller who can supply the code can read and write files as the server OS user, and can persist code execution by writing a .pth file into the server virtualenv\u0027s site-packages. The usual remote path is FastMCP\u0027s GenerativeUI provider, which registers the MCP tool generate_prefab_ui and forwards that tool\u0027s code argument into this sandbox. On a FastMCP server with no authentication configured, any client who can reach the server can call the tool. With authentication, any client allowed to call tools can. Generative UI is opt-in, and the host must have Deno installed. Confirmed on prefab-ui 0.20.2. Fixed in 0.21.0: after the runtime and Prefab sources load, the runner revokes Deno read, write, and network permission before it accepts code, the process is started with --no-prompt so a permission request cannot grant them again, and bootstrap network access is limited to cdn.jsdelivr.net. The fix is commit 030f074 (pull request 538)."
        }
      ],
      "metrics": [
        {
          "cvssV3_1": {
            "attackComplexity": "LOW",
            "attackVector": "NETWORK",
            "availabilityImpact": "HIGH",
            "baseScore": 10,
            "baseSeverity": "CRITICAL",
            "confidentialityImpact": "HIGH",
            "integrityImpact": "HIGH",
            "privilegesRequired": "NONE",
            "scope": "CHANGED",
            "userInteraction": "NONE",
            "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
            "version": "3.1"
          },
          "format": "CVSS",
          "scenarios": [
            {
              "lang": "en",
              "value": "FastMCP server with GenerativeUI enabled, Deno installed, and no authentication configured"
            }
          ]
        },
        {
          "cvssV3_1": {
            "attackComplexity": "LOW",
            "attackVector": "NETWORK",
            "availabilityImpact": "HIGH",
            "baseScore": 9.9,
            "baseSeverity": "CRITICAL",
            "confidentialityImpact": "HIGH",
            "integrityImpact": "HIGH",
            "privilegesRequired": "LOW",
            "scope": "CHANGED",
            "userInteraction": "NONE",
            "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
            "version": "3.1"
          },
          "format": "CVSS",
          "scenarios": [
            {
              "lang": "en",
              "value": "Authenticated client allowed to call tools on a server that executes untrusted code in the Generative UI sandbox"
            }
          ]
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-693",
              "description": "CWE-693: Protection Mechanism Failure",
              "lang": "en",
              "type": "CWE"
            }
          ]
        },
        {
          "descriptions": [
            {
              "cweId": "CWE-94",
              "description": "CWE-94: Improper Control of Generation of Code (\u0027Code Injection\u0027)",
              "lang": "en",
              "type": "CWE"
            }
          ]
        },
        {
          "descriptions": [
            {
              "cweId": "CWE-269",
              "description": "CWE-269: Improper Privilege Management",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-11-01T15:24:54.158Z",
        "orgId": "48a46f29-ae42-4e1d-90dd-c1676c1e5e6d",
        "shortName": "JFROG"
      },
      "references": [
        {
          "name": "Prefab repository",
          "tags": [
            "product"
          ],
          "url": "https://github.com/PrefectHQ/prefab"
        },
        {
          "name": "prefab-ui on PyPI",
          "tags": [
            "product"
          ],
          "url": "https://pypi.org/project/prefab-ui/"
        },
        {
          "name": "GHSA-595q-jv4r-q7j9",
          "tags": [
            "vendor-advisory"
          ],
          "url": "https://github.com/PrefectHQ/prefab/security/advisories/GHSA-595q-jv4r-q7j9"
        },
        {
          "name": "Refresh dependencies and fix renderer and sandbox regressions (fix pull request)",
          "tags": [
            "patch"
          ],
          "url": "https://github.com/PrefectHQ/prefab/pull/538"
        },
        {
          "name": "Fix commit 030f074",
          "tags": [
            "patch"
          ],
          "url": "https://github.com/PrefectHQ/prefab/commit/030f074f85e0b1be0dd44b0283185aecb26337a2"
        },
        {
          "name": "v0.21.0",
          "tags": [
            "release-notes"
          ],
          "url": "https://github.com/PrefectHQ/prefab/releases/tag/v0.21.0"
        },
        {
          "name": "prefab-ui 0.21.0",
          "tags": [
            "release-notes"
          ],
          "url": "https://pypi.org/project/prefab-ui/0.21.0/"
        },
        {
          "name": "v0.20.2 (confirmed affected)",
          "tags": [
            "technical-description"
          ],
          "url": "https://github.com/PrefectHQ/prefab/releases/tag/v0.20.2"
        },
        {
          "name": "v0.14.0 (first release with the sandbox)",
          "tags": [
            "technical-description"
          ],
          "url": "https://github.com/PrefectHQ/prefab/releases/tag/v0.14.0"
        }
      ],
      "source": {
        "discovery": "EXTERNAL"
      },
      "timeline": [
        {
          "lang": "en",
          "time": "2026-03-24T17:21:00.000Z",
          "value": "Pyodide sandbox added with --allow-read, --allow-write, and --allow-net (commit fc4362f3, pull request 334)"
        },
        {
          "lang": "en",
          "time": "2026-03-27T02:36:00.000Z",
          "value": "prefab-ui 0.14.0 published on PyPI, the first release that includes the sandbox"
        },
        {
          "lang": "en",
          "time": "2026-06-03T02:13:00.000Z",
          "value": "prefab-ui 0.20.2 published. This is the release confirmed in testing."
        },
        {
          "lang": "en",
          "time": "2026-08-05T16:12:00.000Z",
          "value": "Reported to PrefectHQ as GHSA-595q-jv4r-q7j9. The advisory is still in triage and has no CVE id."
        },
        {
          "lang": "en",
          "time": "2026-10-25T18:48:00.000Z",
          "value": "Fix merged in pull request 538 (commit 030f074). The runner revokes read, write, and network permission before accepting code."
        },
        {
          "lang": "en",
          "time": "2026-10-26T19:00:00.000Z",
          "value": "prefab-ui 0.21.0 published on PyPI with the fix. No vendor advisory text was published with the release."
        }
      ],
      "title": "Prefab UI Pyodide sandbox escape to host RCE",
      "x_generator": {
        "engine": "Vulnogram 1.0.5"
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "48a46f29-ae42-4e1d-90dd-c1676c1e5e6d",
    "assignerShortName": "JFROG",
    "cveId": "CVE-2026-120338",
    "datePublished": "2026-11-01T15:24:54.158Z",
    "dateReserved": "2026-11-01T15:12:50.987Z",
    "dateUpdated": "2026-11-01T15:24:54.158Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2",
  "vulnerability-lookup:meta": {
    "nvd": {
      "cve": {
        "affected": [
          {
            "affectedData": [
              {
                "collectionURL": "https://pypi.org/project/prefab-ui/",
                "defaultStatus": "unaffected",
                "packageName": "prefab-ui",
                "product": "prefab-ui",
                "programFiles": [
                  "src/prefab_ui/sandbox/_pyodide.py",
                  "src/prefab_ui/sandbox/runner.js"
                ],
                "repo": "git://github.com/PrefectHQ/prefab",
                "vendor": "PrefectHQ",
                "versions": [
                  {
                    "lessThan": "0.21.0",
                    "status": "affected",
                    "version": "0.14.0",
                    "versionType": "semver"
                  }
                ]
              }
            ],
            "source": "reefs@jfrog.com"
          }
        ],
        "cveTags": [],
        "descriptions": [
          {
            "lang": "en",
            "value": "Prefab UI\u0027s Generative UI sandbox runs caller-supplied Python inside Pyodide, Python compiled to WebAssembly, in a Deno subprocess. The feature is documented as isolation for untrusted code, including LLM-written UI. From prefab-ui 0.14.0 through 0.20.2 the launcher starts Deno with unrestricted --allow-read, --allow-write, and --allow-net, and the runner leaves the Deno API on the JavaScript global object. Pyodide\u0027s js module proxies that global, so the Python can call Deno.readTextFileSync and Deno.writeTextFileSync. A caller who can supply the code can read and write files as the server OS user, and can persist code execution by writing a .pth file into the server virtualenv\u0027s site-packages. The usual remote path is FastMCP\u0027s GenerativeUI provider, which registers the MCP tool generate_prefab_ui and forwards that tool\u0027s code argument into this sandbox. On a FastMCP server with no authentication configured, any client who can reach the server can call the tool. With authentication, any client allowed to call tools can. Generative UI is opt-in, and the host must have Deno installed. Confirmed on prefab-ui 0.20.2. Fixed in 0.21.0: after the runtime and Prefab sources load, the runner revokes Deno read, write, and network permission before it accepts code, the process is started with --no-prompt so a permission request cannot grant them again, and bootstrap network access is limited to cdn.jsdelivr.net. The fix is commit 030f074 (pull request 538)."
          }
        ],
        "id": "CVE-2026-120338",
        "lastModified": "2026-11-01T16:18:14.970",
        "metrics": {
          "cvssMetricV31": [
            {
              "cvssData": {
                "attackComplexity": "LOW",
                "attackVector": "NETWORK",
                "availabilityImpact": "HIGH",
                "baseScore": 10.0,
                "baseSeverity": "CRITICAL",
                "confidentialityImpact": "HIGH",
                "integrityImpact": "HIGH",
                "privilegesRequired": "NONE",
                "scope": "CHANGED",
                "userInteraction": "NONE",
                "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
                "version": "3.1"
              },
              "exploitabilityScore": 3.9,
              "impactScore": 6.0,
              "source": "reefs@jfrog.com",
              "type": "Secondary"
            }
          ]
        },
        "published": "2026-11-01T16:18:14.970",
        "references": [
          {
            "source": "reefs@jfrog.com",
            "url": "https://github.com/PrefectHQ/prefab"
          },
          {
            "source": "reefs@jfrog.com",
            "url": "https://github.com/PrefectHQ/prefab/commit/030f074f85e0b1be0dd44b0283185aecb26337a2"
          },
          {
            "source": "reefs@jfrog.com",
            "url": "https://github.com/PrefectHQ/prefab/pull/538"
          },
          {
            "source": "reefs@jfrog.com",
            "url": "https://github.com/PrefectHQ/prefab/releases/tag/v0.14.0"
          },
          {
            "source": "reefs@jfrog.com",
            "url": "https://github.com/PrefectHQ/prefab/releases/tag/v0.20.2"
          },
          {
            "source": "reefs@jfrog.com",
            "url": "https://github.com/PrefectHQ/prefab/releases/tag/v0.21.0"
          },
          {
            "source": "reefs@jfrog.com",
            "url": "https://github.com/PrefectHQ/prefab/security/advisories/GHSA-595q-jv4r-q7j9"
          },
          {
            "source": "reefs@jfrog.com",
            "url": "https://pypi.org/project/prefab-ui/"
          },
          {
            "source": "reefs@jfrog.com",
            "url": "https://pypi.org/project/prefab-ui/0.21.0/"
          }
        ],
        "sourceIdentifier": "reefs@jfrog.com",
        "vulnStatus": "Received",
        "weaknesses": [
          {
            "description": [
              {
                "lang": "en",
                "value": "CWE-94"
              },
              {
                "lang": "en",
                "value": "CWE-269"
              },
              {
                "lang": "en",
                "value": "CWE-693"
              }
            ],
            "source": "reefs@jfrog.com",
            "type": "Primary"
          }
        ]
      }
    }
  }
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline

Sightings and recorded dates, grouped by day · UTC

JSON
Events included in the timeline

Loading timeline…


    Loading…

    Loading…

    Loading…

    Related by attack behaviour

    Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.