e4a9d76ade3f47b267e8c418ef6c8d7faa4e430c Exclude chrome-untrusted:// from access to the unbounded API
The bug at a glance
chrome-untrusted:// documents were incorrectly granted the privileged ‘unbounded element’ API, a capability docs/webui/chrome_untrusted.md says such pages must never receive (they are meant to carry no privileges beyond a normal renderer). chrome-untrusted:// is the sandboxed scheme used to host untrustworthy or web-derived content inside WebUI surfaces, so leaking a privileged API into it widens that content’s capability surface. Severity is low because the API itself is a layout/rendering capability gated behind a feature flag (kUnboundedElement), not a direct memory-safety or cross-origin data primitive, and reaching the vulnerable path still requires loading content into a chrome-untrusted:// frame.
Blink/content classified any origin for which IsWebUI()/HasWebUIOrigin() returns true as privileged for the unbounded element API, but IsWebUI() returns true for chrome-untrusted:// as well as chrome:// . The scheme that is explicitly supposed to be de-privileged therefore inherited a WebUI-only privilege.
Root cause
Three parallel privilege checks (browser-side RenderFrameHostImpl, renderer-side RenderFrameImpl, and Blink ContextFeatureSettings) each granted kAllowedPrivileged / enabled the V8 feature whenever the origin was a WebUI origin. Because SecurityOrigin::IsWebUI() and HasWebUIOrigin() treat chrome-untrusted:// as a WebUI scheme, a chrome-untrusted:// context satisfied the privileged branch. The patch adds an explicit scheme comparison (scheme/Protocol != chrome-untrusted) to every branch so the untrusted scheme falls through to the normal (open-web / denied) path.
Key code
Browser-side authorization now excludes chrome-untrusted:// before returning kAllowedPrivileged.
- if (web_ui() != nullptr || HasWebUIOrigin(GetLastCommittedOrigin())) {
+ if (GetLastCommittedOrigin().scheme() != kChromeUIUntrustedScheme &&
+ (web_ui() != nullptr || HasWebUIOrigin(GetLastCommittedOrigin()))) {
return UnboundedElementAuth::kAllowedPrivileged;
}
Patch walkthrough
content/browser/renderer_host/render_frame_host_impl.cc— The browser-process authority (GetUnboundedElementAuth-style check) returned kAllowedPrivileged for any WebUI frame. The guard now also requires GetLastCommittedOrigin().scheme() != kChromeUIUntrustedScheme, so a chrome-untrusted:// frame no longer receives the privileged grant from the browser side.content/renderer/render_frame_impl.cc— The renderer computed is_unbounded_allowed partly from GetSecurityOrigin().IsWebUI(); it now additionally requires the origin’s Protocol() != kChromeUIUntrustedScheme before calling WebV8Features::EnableUnboundedElement(context, true), closing the renderer-side enabling path.third_party/blink/renderer/core/context_features/context_feature_settings.cc— Blink’s is_privileged computation (security_origin->IsWebUI()) now also checks Protocol() != “chrome-untrusted”; the accompanying comment is updated to say IsWebUI() is used ’excluding chrome-untrusted’. This is the deepest layer and the component the prescan flagged.
Background
chrome-untrusted:// — A scheme for WebUI-adjacent pages that render content Chrome does not fully trust (e.g. media, remote resources). Per docs/webui/chrome_untrusted.md it must receive no privileges beyond a normal renderer, yet it is still a ‘WebUI’ scheme for IsWebUI() purposes.
Unbounded element API — A privileged, feature-flag-gated (kUnboundedElement / kUnboundedElementOnTheOpenWeb) capability intended for trusted WebUI surfaces. Privileged access returns UnboundedElementAuth::kAllowedPrivileged.
SecurityOrigin::IsWebUI() / HasWebUIOrigin() — Predicates that classify an origin as a WebUI scheme. They return true for both chrome:// and chrome-untrusted://, which is the root of the over-grant.
Vulnerability window
- Introduction — When the unbounded element privilege checks were written keyed on IsWebUI()/HasWebUIOrigin(), chrome-untrusted:// was swept in as a privileged WebUI scheme (inferred).
- Discovery — Tracked internally as Fixed: 553138969; identified as a mismatch with the chrome-untrusted:// no-extra-privileges policy (inferred).
- Fix — 2026-09-03, commit by Mason Freed, reviewed by Rakina Zata Amni: scheme exclusion added at all three enforcement layers.
Proof of concept
Conceptual only. A chrome-untrusted:// page (reachable where WebUI embeds untrusted content) with the kUnboundedElement feature enabled would, before this fix, successfully use the unbounded element API because the authorization layers returned the privileged grant for its WebUI scheme. No concrete exploit is constructed here and the capability is a rendering feature, not a memory primitive.
Exploitation
- Setup — Attacker-influenced content is loaded into a chrome-untrusted:// frame (the scheme used to host untrusted content inside WebUI). (inferred)
- Abuse — The content invokes the unbounded element API, which the browser/renderer/Blink layers wrongly authorized because the frame’s origin is classified as WebUI. (inferred)
- Impact — Untrusted content gains a privilege it should never hold, violating the chrome-untrusted:// isolation contract and expanding its attack surface. (inferred)
Detection & hunting
For defenders and detection engineers:
- UnboundedElementAuth::kAllowedPrivileged granted to a chrome-untrusted:// origin — Audit any logging/telemetry that records privileged unbounded-element grants and confirm no chrome-untrusted:// origins appear in post-patch builds.
- WebV8Features::EnableUnboundedElement enabled in a chrome-untrusted:// renderer context — In the renderer, verify the feature is not enabled for contexts whose SecurityOrigin Protocol is chrome-untrusted.
Audit directions
- Other IsWebUI()/HasWebUIOrigin()-gated privileges — Grep for privilege or capability checks keyed solely on IsWebUI()/HasWebUIOrigin()/kWebUi bindings; each is a candidate for the same chrome-untrusted:// over-grant and should be re-examined against docs/webui/chrome_untrusted.md.
- Feature-flag-gated WebUI APIs — Review APIs enabled per-context from the renderer or Blink that trust the WebUI scheme without re-checking against the untrusted sub-scheme.