diff --git a/scripts/check_new_install_scripts.py b/scripts/check_new_install_scripts.py index a536c9bbe1..18cad0a25c 100644 --- a/scripts/check_new_install_scripts.py +++ b/scripts/check_new_install_scripts.py @@ -372,6 +372,31 @@ def main(argv: list[str] | None = None) -> int: ) return 1 + # Also refuse a PR that DROPS trusted base entries. Without + # this, an attacker could land a two-step bypass: + # 1. PR A removes ``.install-script-allowlist`` from base + # (passes -- no new lockfile findings). + # 2. PR B then hits the bootstrap path (base allowlist + # missing) and self-allowlists a newly introduced + # install-script dependency. + # Removing an allowlist entry is a security-sensitive change + # and must land via the same review path that added it. + removed_from_head = sorted(base_allowlist - head_allowlist) + if removed_from_head: + print( + "[install-script-diff] FAIL: PR removes trusted base " + "allowlist entries. Allowlist deletions must land in a " + "separate, isolated commit so a follow-up PR cannot " + "exploit the bootstrap path.", + file = sys.stderr, + ) + for entry in removed_from_head: + print( + f" dropped allowlist entry: {entry}", + file = sys.stderr, + ) + return 1 + # Only the trusted base allowlist participates in the skip set. allowlist = base_allowlist diff --git a/studio/frontend/src/components/assistant-ui/__tests__/html-svg-renderer.test.tsx b/studio/frontend/src/components/assistant-ui/__tests__/html-svg-renderer.test.tsx index 2b13345ed2..7a89654c11 100644 --- a/studio/frontend/src/components/assistant-ui/__tests__/html-svg-renderer.test.tsx +++ b/studio/frontend/src/components/assistant-ui/__tests__/html-svg-renderer.test.tsx @@ -268,12 +268,19 @@ describe("sanitizeSvgSource", () => { expect(clean).toContain(" blocks so SVG CSS cannot retarget host selectors", () => { - const svg = ``; + it("keeps inline `; const clean = sanitizeSvgSource(svg).toLowerCase(); - expect(clean).not.toContain(" { diff --git a/studio/frontend/src/components/assistant-ui/html-svg-renderer.tsx b/studio/frontend/src/components/assistant-ui/html-svg-renderer.tsx index d257ab9756..526c4f2a1a 100644 --- a/studio/frontend/src/components/assistant-ui/html-svg-renderer.tsx +++ b/studio/frontend/src/components/assistant-ui/html-svg-renderer.tsx @@ -53,13 +53,17 @@ const HEURISTIC_UNSAFE_SVG_RE = // https://developer.mozilla.org/en-US/docs/Web/SVG/Guides/SVG_as_an_image const SVG_PURIFY_CONFIG = { USE_PROFILES: { svg: true, svgFilters: true }, - // ``style`` -- inline CSS would otherwise leak to the host page selectors. // ``image`` / ``use`` -- carry ``href``/``xlink:href`` and would let an // assistant fetch attacker-controlled URLs from the user's browser. // ``foreignObject`` -- can embed HTML inside the SVG and re-introduce XSS. + // ``script`` / ``link`` / ``meta`` / ``iframe`` / ``embed`` / ``object`` + // are unconditional XSS / network surfaces. ``