Medium CVSS 6.5 firefox Policy Bypass 🔧 Commit mapped

Overview

Medium
Severity
6.5
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionFirefox could have incorrectly parsed a URL and rewritten it to the youtube.com domain when parsing the URL specified in an <code>embed</code> tag. This could have bypassed website security checks that restricted which domains users were allowed to embed.
ComponentDOM
Bug ClassPolicy Bypass
Tracker1970658
Fix commit7ef2c4c3642a (firefox) +11/-9
CWECWE-116
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N
CISA KEVNot listed
CreditedMasato Kinugawa
Disclosed2025-06-24

Background

`nsIURI::GetSpec` vs `GetPrePath`
GetSpec returns the entire serialized URI (scheme + authority/host + path + query). GetPrePath returns only the scheme://host[:port] prefix; the path/query is a separate component (path in the patched code).
String rewrite ops
The routine runs FindChar('&'/'?'), ReplaceChar('?','&'), SetCharAt, and ReplaceSubstring("/v/","/embed/") over the URL text before re-parsing it with NewURIWithDocumentCharset.
Embed domain restrictions
Sites may restrict which domains can be embedded; the rewrite result determines the effective embedded origin.

Root Cause Analysis

The old code fetched the whole URL with aURI->GetSpec(uri) and then performed all of its character searches and substring replacements over that single string — including scheme and host. Because the search for &/? and the "/v/" → "/embed/" replacement operated on the complete spec, a crafted URL whose authority or path was arranged so these operations matched in the host region (or shifted the ?/& boundary) could be mutated such that, after re-parsing with NewURIWithDocumentCharset, the effective host became youtube.com. In other words, the rewrite incorrectly reinterpreted parts of the URL and could relocate the domain, letting an attacker produce a rewritten embed URL on the youtube.com origin from an input that was not genuinely a youtube.com URL — bypassing site checks that gate which domains may be embedded.

The patch separates the immutable authority from the mutable path: it replaces GetSpec(uri) with GetPrePath(prePath), and performs every FindChar, ReplaceChar, SetCharAt, and ReplaceSubstring("/v/","/embed/") operation on the path component only. The final URL is reconstructed by concatenating the untouched prePath with the rewritten path (NS_ConvertUTF8toUTF16 utf16URI(prePath); AppendUTF8toUTF16(path, utf16URI);). Keeping the scheme/host out of the string surgery means the rewrite can no longer alter the origin. The advisory (CWE-116, improper neutralization) and the diff agree that the root cause is performing origin-affecting string manipulation over the full URL spec instead of the path alone.

Key insight
The YouTube-embed rewriter ran its &/? and /v/→/embed/ string surgery over the entire URL spec including scheme and host, so a crafted input could be mutated into a youtube.com-origin URL; the fix confines all edits to the path component and keeps the pre-path (origin) untouched.

Attack Path

  1. Craft embed Attacker supplies an <embed>/<object> whose URL is constructed so the rewrite’s char/substring operations misfire across the authority/path boundary. (web-reachable)
  2. Trigger rewrite Object loading invokes MaybeRewriteYoutubeEmbed, which reads the full spec and runs its replacements over it.
  3. Origin relocation The /v/→/embed/ replacement and ?/& juggling mutate the string such that re-parsing yields an effective host of youtube.com.
  4. Bypass check A site that restricts embeddable domains is tricked: the resource is now treated as a youtube.com embed despite the original URL not being a legitimate youtube.com resource.
  5. Primitive Bypass of embed-domain restrictions, loading content under/as the youtube.com origin against the site’s intent (integrity impact, CVSS 6.5).

Impact Assessment

The flaw is in the content process and reachable from any page containing an <embed>/<object> tag (UI:R). The gained capability is a logic/parsing bypass: an attacker can cause a URL to be rewritten to the youtube.com domain and thereby evade a site’s restriction on which domains may be embedded. It is not memory corruption and not direct code execution; the impact is an integrity-level security-check bypass whose severity depends on how the targeted site relies on embed-domain gating.

Changed Functions

FunctionChangeNotes
if
dom/base/nsObjectLoadingContent.cpp
modified

Files Changed

  • dom/base/nsObjectLoadingContent.cpp

Audit Directions

  • Spec-wide string surgery on URIs
    Search for other code that calls GetSpec and then does Replace*/FindChar/SetCharAt before re-parsing; such patterns can relocate the authority.
  • URL rewriting / canonicalization paths
    Audit other legacy embed/compat rewriters and redirect builders for operating on whole specs rather than components.
  • Re-parse trust boundaries
    Review NewURIWithDocumentCharset callers that feed it a string assembled from partially-attacker-controlled fragments.
diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp
index 26419de69eb..45549fceffe 100644
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -539,8 +539,8 @@ void nsObjectLoadingContent::MaybeRewriteYoutubeEmbed(nsIURI* aURI,
   }
 
   // See if requester is planning on using the JS API.
-  nsAutoCString uri;
-  nsresult rv = aURI->GetSpec(uri);
+  nsAutoCString prePath;
+  nsresult rv = aURI->GetPrePath(prePath);
   if (NS_FAILED(rv)) {
     return;
   }
@@ -551,10 +551,10 @@ void nsObjectLoadingContent::MaybeRewriteYoutubeEmbed(nsIURI* aURI,
   // URLs, convert the parameters to query in order to make the video load
   // correctly as an iframe. In either case, warn about it in the
   // developer console.
-  int32_t ampIndex = uri.FindChar('&', 0);
+  int32_t ampIndex = path.FindChar('&', 0);
   bool replaceQuery = false;
   if (ampIndex != -1) {
-    int32_t qmIndex = uri.FindChar('?', 0);
+    int32_t qmIndex = path.FindChar('?', 0);
     if (qmIndex == -1 || qmIndex > ampIndex) {
       replaceQuery = true;
     }
@@ -570,19 +570,21 @@ void nsObjectLoadingContent::MaybeRewriteYoutubeEmbed(nsIURI* aURI,
     return;
   }
 
-  nsAutoString utf16OldURI = NS_ConvertUTF8toUTF16(uri);
+  NS_ConvertUTF8toUTF16 utf16OldURI(prePath);
+  AppendUTF8toUTF16(path, utf16OldURI);
   // If we need to convert the URL, it means an ampersand comes first.
   // Use the index we found earlier.
   if (replaceQuery) {
     // Replace question marks with ampersands.
-    uri.ReplaceChar('?', '&');
+    path.ReplaceChar('?', '&');
     // Replace the first ampersand with a question mark.
-    uri.SetCharAt('?', ampIndex);
+    path.SetCharAt('?', ampIndex);
   }
   // Switch out video access url formats, which should possibly allow HTML5
   // video loading.
-  uri.ReplaceSubstring("/v/"_ns, "/embed/"_ns);
-  nsAutoString utf16URI = NS_ConvertUTF8toUTF16(uri);
+  path.ReplaceSubstring("/v/"_ns, "/embed/"_ns);
+  NS_ConvertUTF8toUTF16 utf16URI(prePath);
+  AppendUTF8toUTF16(path, utf16URI);
   rv = nsContentUtils::NewURIWithDocumentCharset(aRewrittenURI, utf16URI, doc,
                                                  aBaseURI);
   if (NS_FAILED(rv)) {
Loading diff…