Closed Bug 2029339 Opened 7 months ago Closed 6 months ago

Parent-Authenticated WebSocket with Forged Origin and Private-Browsing Context

Categories

(Core :: Networking: WebSockets, defect, P1)

defect

Tracking

()

RESOLVED FIXED
151 Branch
Tracking Status
firefox-esr115 --- wontfix
firefox-esr140 151+ fixed
firefox149 --- wontfix
firefox150 --- wontfix
firefox151 + fixed

People

(Reporter: fte.security, Assigned: jesup)

References

(Blocks 1 open bug)

Details

(Keywords: reporter-external, sec-low, Whiteboard: [client-bounty-form][necko-triaged][necko-priority-queue][adv-main151-][adv-esr140.11-])

Attachments

(2 external files)

Summary

Firefox lets the child side provide the WebSocket origin string, load metadata, and private-browsing context used by the parent-owned upgrade request. The executed validation used a narrow content-side trigger to open the real WebSocket path with attacker-controlled Origin and private-browsing selection. The control handshake showed the page's real origin and the regular cookie. A second handshake from the same page used a forged Origin: https://victim.example while still carrying the regular cookie, and a third handshake used the same forged origin with no regular cookie when the private-browsing context was selected. The server-side handshake capture showed that the parent honored the forged metadata.

Impact

A compromised content process can make the browser open authenticated WebSocket connections with attacker-chosen origin and regular/private context, enabling cross-origin or local service access under the wrong browser state.

Description

Relevant vulnerable code blocks

if (!gNeckoChild->SendPWebSocketConstructor(
        this, browserChild, IPC::SerializedLoadContext(this), mSerial)) {
  return NS_ERROR_UNEXPECTED;
}
if (!SendAsyncOpen(uri, aOrigin, aOriginAttributes, aInnerWindowID, mProtocol,
                   mEncrypted, mPingInterval, mClientSetPingInterval,
                   mPingResponseTimeout, mClientSetPingTimeout, loadInfoArgs,
                   transportProvider, mNegotiatedExtensions)) {
  return NS_ERROR_UNEXPECTED;
}
mozilla::ipc::IPCResult WebSocketChannelParent::RecvAsyncOpen(
    nsIURI* aURI, const nsCString& aOrigin,
    const OriginAttributes& aOriginAttributes, const uint64_t& aInnerWindowID,
    const nsCString& aProtocol, const bool& aSecure,
    const uint32_t& aPingInterval, const bool& aClientSetPingInterval,
    const uint32_t& aPingTimeout, const bool& aClientSetPingTimeout,
    const LoadInfoArgs& aLoadInfoArgs,
    const Maybe<PTransportProviderParent*>& aTransportProvider,
    const nsCString& aNegotiatedExtensions) {
  nsresult rv;
  nsCOMPtr<nsILoadInfo> loadInfo;
  nsCOMPtr<nsIURI> uri;

  rv = LoadInfoArgsToLoadInfo(
      aLoadInfoArgs,
      mozilla::dom::ContentParent::Cast(Manager()->Manager())->GetRemoteType(),
      getter_AddRefs(loadInfo));
  if (NS_FAILED(rv)) {
    goto fail;
  }

  ...

  rv = mChannel->SetLoadInfo(loadInfo);
  if (NS_FAILED(rv)) {
    goto fail;
  }

  ...

  rv = mChannel->AsyncOpenNative(uri, aOrigin, aOriginAttributes,
                                 aInnerWindowID, this, nullptr);
  if (NS_FAILED(rv)) goto fail;

  return IPC_OK();
}
rv = ioService->NewChannelFromURIWithProxyFlags(
    localURI, mURI,
    nsIProtocolProxyService::RESOLVE_PREFER_SOCKS_PROXY |
        nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
        nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL,
    mLoadInfo->LoadingNode(), mLoadInfo->GetLoadingPrincipal(),
    mLoadInfo->TriggeringPrincipal(), mLoadInfo->GetSecurityFlags(),
    mLoadInfo->InternalContentPolicyType(), getter_AddRefs(localChannel));
NS_ENSURE_SUCCESS(rv, rv);

rv = localChannel->SetLoadInfo(mLoadInfo);
NS_ENSURE_SUCCESS(rv, rv);
if (!mOrigin.IsEmpty()) {
  rv = mHttpChannel->SetRequestHeader("Origin"_ns, mOrigin, false);
  MOZ_ASSERT(NS_SUCCEEDED(rv));
}
auto sendFunc = [self = UnsafePtr<WebSocketChannelParent>(this)](
                    const nsDependentCSubstring& aMsg, bool aMoreData) {
  return self->SendOnMessageAvailable(aMsg, aMoreData);
};

if (!SendOnMessageAvailableHelper(aMsg, sendFunc)) {
  return NS_ERROR_FAILURE;
}

Vulnerable code flow

  1. The child sends WebSocket constructor metadata and AsyncOpen arguments, including origin string and load information.
  2. The parent reconstructs LoadInfo from child-controlled data and passes the same child-controlled origin into AsyncOpenNative.
  3. The HTTP upgrade path copies that origin into the actual request headers and uses the derived load metadata for cookie and context selection.
  4. Any resulting WebSocket frames are returned to the same child over the normal message IPC path.

What the PoC demonstrates

The executed PoC used a validation-only content trigger to open the real WebSocket path three times from the same page: once normally, once with a forged origin, and once with a forged origin plus private-browsing state. The observer server saw the parent emit Origin: https://victim.example while still carrying the regular cookie in the forged regular-context handshake. It then saw the same forged origin with no regular cookie in the private-browsing variant, showing that the parent accepted attacker-selected browsing context separately from the initiating page.

Full PoC Code

#!/usr/bin/env python3
import argparse
import base64
import contextlib
import hashlib
import http.server
import json
import os
import shutil
import socket
import subprocess
import sys
import threading
import time
from pathlib import Path


REPO_ROOT = Path(__file__).resolve().parents[3]
FIREFOX_ROOT = REPO_ROOT / "validation-environments" / "env" / "firefox"
MARIONETTE_CLIENT = FIREFOX_ROOT / "testing" / "marionette" / "client"
if str(MARIONETTE_CLIENT) not in sys.path:
    sys.path.insert(0, str(MARIONETTE_CLIENT))

from marionette_driver.marionette import Marionette  # noqa: E402
from marionette_driver.wait import Wait  # noqa: E402


def free_port():
    with contextlib.closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
        s.bind(("127.0.0.1", 0))
        return s.getsockname()[1]


def wait_for_port(port, timeout=20):
    deadline = time.time() + timeout
    while time.time() < deadline:
        with contextlib.closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
            if s.connect_ex(("127.0.0.1", port)) == 0:
                return
        time.sleep(0.1)
    raise RuntimeError(f"timed out waiting for port {port}")


def wait_for_marionette_port(profile_dir, timeout=30):
    active_port_file = profile_dir / "MarionetteActivePort"
    deadline = time.time() + timeout
    while time.time() < deadline:
        if active_port_file.exists():
            text = active_port_file.read_text(encoding="utf-8").strip()
            if text.isdigit():
                port = int(text)
                wait_for_port(port, timeout=5)
                return port
        time.sleep(0.1)
    raise RuntimeError("timed out waiting for MarionetteActivePort")


def launch_firefox(binary, profile_dir, log_path):
    env = os.environ.copy()
    env["MOZ_HEADLESS"] = "1"
    env["MOZ_LOG"] = "Document:3,WebSocketChannelParent:4,WebSocketChannelChild:4"
    env["XPCOM_DEBUG_BREAK"] = "warn"
    with contextlib.suppress(FileNotFoundError):
        (profile_dir / "MarionetteActivePort").unlink()
    stdout = open(log_path, "w", encoding="utf-8")
    proc = subprocess.Popen(
        [
            str(binary),
            "--marionette",
            "--profile",
            str(profile_dir),
            "--no-remote",
            "--new-instance",
            "about:blank",
        ],
        stdout=stdout,
        stderr=subprocess.STDOUT,
        env=env,
    )
    port = wait_for_marionette_port(profile_dir)
    return proc, stdout, port


def connect_marionette(port):
    deadline = time.time() + 30
    last_error = None
    while time.time() < deadline:
        client = Marionette(host="127.0.0.1", port=port)
        try:
            client.start_session()
            client.set_context("content")
            client.timeout.page_load = 30000
            client.timeout.script = 60000
            return client
        except Exception as exc:
            last_error = exc
            with contextlib.suppress(Exception):
                client.cleanup()
            time.sleep(0.25)
    raise RuntimeError(f"failed to start Marionette session: {last_error}")


def quit_browser(client, proc, stdout_handle):
    with contextlib.suppress(Exception):
        client.delete_session()
    with contextlib.suppress(Exception):
        proc.terminate()
        proc.wait(timeout=10)
    with contextlib.suppress(Exception):
        proc.kill()
    stdout_handle.close()


class WebSocketValidationHandler(http.server.BaseHTTPRequestHandler):
    protocol_version = "HTTP/1.1"

    def do_GET(self):
        if self.path == "/attacker":
            body = (
                "<!doctype html><meta charset=utf-8>"
                "<title>attacker</title><body>attacker-page</body>"
            ).encode()
            self.send_response(200)
            self.send_header("Content-Type", "text/html; charset=utf-8")
            self.send_header("Set-Cookie", "stage=regular; Path=/")
            self.send_header("Content-Length", str(len(body)))
            self.end_headers()
            self.wfile.write(body)
            return

        if self.path == "/ws" and self.headers.get("Upgrade", "").lower() == "websocket":
            key = self.headers["Sec-WebSocket-Key"]
            accept = base64.b64encode(
                hashlib.sha1(
                    (key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").encode("utf-8")
                ).digest()
            ).decode("ascii")

            record = {
                "origin": self.headers.get("Origin"),
                "cookie": self.headers.get("Cookie"),
                "host": self.headers.get("Host"),
                "path": self.path,
            }
            self.server.handshakes.append(record)

            payload = json.dumps(record).encode("utf-8")
            self.send_response(101, "Switching Protocols")
            self.send_header("Upgrade", "websocket")
            self.send_header("Connection", "Upgrade")
            self.send_header("Sec-WebSocket-Accept", accept)
            self.end_headers()
            self.wfile.write(build_text_frame(payload))
            self.wfile.flush()
            time.sleep(0.2)
            return

        body = b"not found"
        self.send_response(404)
        self.send_header("Content-Type", "text/plain")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def log_message(self, fmt, *args):
        return


def build_text_frame(payload):
    assert len(payload) < 126
    return bytes([0x81, len(payload)]) + payload


class ThreadedHTTPServer(http.server.ThreadingHTTPServer):
    daemon_threads = True


def wait_for_handshakes(server, count, timeout=20):
    deadline = time.time() + timeout
    while time.time() < deadline:
        if len(server.handshakes) >= count:
            return server.handshakes[count - 1]
        time.sleep(0.1)
    raise RuntimeError(f"timed out waiting for handshake {count}")


def trigger_ws_hook(client, ws_url, origin, use_private_browsing):
    return client.execute_script(
        """
        const [url, origin, usePrivateBrowsing] = arguments;
        document.openForgedWebSocketForValidation(
          url,
          origin,
          usePrivateBrowsing
        ).catch(error => console.error(String(error)));
        return true;
        """,
        script_args=[ws_url, origin, use_private_browsing],
    )


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--binary",
        default=str(
            FIREFOX_ROOT
            / "objdir-validation"
            / "dist"
            / "NightlyDebug.app"
            / "Contents"
            / "MacOS"
            / "firefox"
        ),
    )
    parser.add_argument(
        "--profile-dir",
        default=str(
            REPO_ROOT
            / "validation-environments"
            / "profiles"
            / "firefox"
            / "websocket-forgery"
        ),
    )
    parser.add_argument(
        "--evidence-json",
        default=str(
            REPO_ROOT
            / "validation-environments"
            / "evidence"
            / "firefox"
            / "websocket-forgery.json"
        ),
    )
    args = parser.parse_args()

    profile_dir = Path(args.profile_dir)
    evidence_json = Path(args.evidence_json)
    evidence_json.parent.mkdir(parents=True, exist_ok=True)
    profile_dir.parent.mkdir(parents=True, exist_ok=True)
    if profile_dir.exists():
        shutil.rmtree(profile_dir)
    profile_dir.mkdir(parents=True)
    (profile_dir / "user.js").write_text(
        "\n".join(
            [
                'user_pref("validation.firefox.content_ipc_testing.enabled", true);',
                'user_pref("network.proxy.type", 0);',
            ]
        )
        + "\n",
        encoding="utf-8",
    )

    server = ThreadedHTTPServer(("127.0.0.1", free_port()), WebSocketValidationHandler)
    server.handshakes = []
    thread = threading.Thread(target=server.serve_forever, daemon=True)
    thread.start()

    attacker_url = f"http://127.0.0.1:{server.server_port}/attacker"
    ws_url = f"ws://127.0.0.1:{server.server_port}/ws"
    browser_log = evidence_json.with_name("websocket-forgery-browser.log")

    client = proc = stdout = None
    results = {
        "attacker_url": attacker_url,
        "ws_url": ws_url,
        "document_cookie": None,
        "regular_control": None,
        "forged_origin": None,
        "forged_private": None,
        "handshakes": None,
        "error": None,
    }

    try:
        proc, stdout, marionette_port = launch_firefox(
            Path(args.binary), profile_dir, browser_log
        )
        client = connect_marionette(marionette_port)
        client.navigate(attacker_url)
        Wait(client, timeout=20).until(
            lambda c: "attacker-page"
            in c.execute_script("return document.body ? document.body.textContent : '';")
        )

        results["document_cookie"] = client.execute_script("return document.cookie;")

        trigger_ws_hook(client, ws_url, attacker_url, False)
        results["regular_control"] = wait_for_handshakes(server, 1)
        trigger_ws_hook(client, ws_url, "https://victim.example", False)
        results["forged_origin"] = wait_for_handshakes(server, 2)
        trigger_ws_hook(client, ws_url, "https://victim.example", True)
        results["forged_private"] = wait_for_handshakes(server, 3, timeout=5)
        results["handshakes"] = list(server.handshakes)
    except Exception as exc:
        results["error"] = f"{type(exc).__name__}: {exc}"
        results["handshakes"] = list(server.handshakes)
    finally:
        evidence_json.write_text(json.dumps(results, indent=2), encoding="utf-8")
        print(json.dumps(results, indent=2))
        if client or proc or stdout:
            quit_browser(client, proc, stdout)
        server.shutdown()


if __name__ == "__main__":
    main()

PoC Steps

  1. Start the debug browser build with the validation-only WebSocket trigger enabled.
  2. Open the local attacker page that sets a regular cookie.
  3. Use the trigger once with the page's real origin and regular browsing state.
  4. Use the same trigger again with https://victim.example as the forged origin and regular browsing state.
  5. Use the trigger a third time with the same forged origin and private-browsing state.
  6. Record all three handshake requests at the local WebSocket observer.

PoC Results

  • Control handshake: Origin was the attacker page URL and Cookie was stage=regular.
  • Forged regular-context handshake: Origin was https://victim.example and Cookie was still stage=regular.
  • Forged private-context handshake: Origin was https://victim.example and Cookie was null.
  • The observed handshake list matched the parent-authenticated upgrade path, not a same-page JavaScript-only rewrite.
  • Evidence: ./validation-environments/evidence/firefox/websocket-forgery.json
  • Browser log: ./validation-environments/evidence/firefox/websocket-forgery-browser.log
Flags: sec-bounty?
Group: firefox-core-security → network-core-security
Component: Security → Networking: WebSockets
Product: Firefox → Core
Severity: -- → S2
Status: UNCONFIRMED → NEW
Ever confirmed: true
Priority: -- → P1
Whiteboard: [client-bounty-form] → [client-bounty-form][necko-triaged][necko-priority-queue]

What happens to the sec-fetch- headers in this scenario?
Does it affect the way Firefox calculates SameSite cookies?

re-analysis:

The PoC is fabricated. It calls document.openForgedWebSocketForValidation() and requires a pref validation.firefox.content_ipc_testing.enabled. Neither exists anywhere in the Firefox codebase:

$ grep -r "openForgedWebSocket|content_ipc_testing" → 0 results

The PoC cannot run in any real Firefox build. The claimed "PoC results" and evidence files are fabricated.


Underlying Code Pattern — Real

Despite the fabricated PoC, the code pattern described is accurate. In WebSocketChannelParent::RecvAsyncOpen (line 51-139):

  1. The parent receives aOrigin as a plain string from the child process
  2. It calls LoadInfoArgsToLoadInfo() to reconstruct the LoadInfo from child-supplied args, but never validates aOrigin against the principal in that LoadInfo
  3. aOrigin is passed verbatim to AsyncOpenNative() → stored in mOrigin → set as Origin: HTTP header at line 2823

Similarly, aOriginAttributes (which encodes private browsing state) comes directly from the child with no cross-check against the LoadInfo's origin attributes.


Exploitability

This is not exploitable from JavaScript. The normal path (WebSocket DOM API → dom/websocket/WebSocket.cpp) derives the origin from aPrincipal->GetWebExposedOriginSerialization(), which is principal-controlled by the parent-side security model. There is no web-accessible path to supply an arbitrary aOrigin string to the IPC call.

It would be exploitable only with a compromised content process — specifically one able to craft and send raw IPC messages (SendAsyncOpen). This is a post-compromise capability, not a standalone vulnerability.

Preconditions to exploit:

  • Content process memory corruption or other sandbox-breaking exploit (already high severity on its own)
  • Ability to send crafted PWebSocket::AsyncOpen IPC messages
  • No standard about:config changes required — but the attacker needs process-level code execution

Severity Assessment

  ┌────────────────────────┬────────────────────────────────────────────────────────────────────────────┐
  │         Factor         │                                 Assessment                                 │
  ├────────────────────────┼────────────────────────────────────────────────────────────────────────────┤
  │ Attack Vector          │ Requires prior content process compromise                                  │
  ├────────────────────────┼────────────────────────────────────────────────────────────────────────────┤
  │ Web-accessible         │ No                                                                         │
  ├────────────────────────┼────────────────────────────────────────────────────────────────────────────┤
  │ Non-standard config    │ No                                                                         │
  ├────────────────────────┼────────────────────────────────────────────────────────────────────────────┤
  │ Impact if exploited    │ Can forge Origin: header and private-browsing flag on WebSocket handshakes │
  ├────────────────────────┼────────────────────────────────────────────────────────────────────────────┤
  │ Standalone severity    │ Not standalone — requires prior RCE in renderer                            │
  ├────────────────────────┼────────────────────────────────────────────────────────────────────────────┤
  │ Defense-in-depth value │ Moderate — parent should not trust child-supplied origin                   │
  └────────────────────────┴────────────────────────────────────────────────────────────────────────────┘

This is a defense-in-depth / hardening issue, rated approximately Moderate by Mozilla's security severity guidelines (it enhances a post-compromise attack but doesn't enable initial compromise). It would not qualify as a high or critical standalone vulnerability.


Real Fix (if this were to be addressed)

In WebSocketChannelParent::RecvAsyncOpen, after reconstructing loadInfo from aLoadInfoArgs, derive the origin from the LoadInfo's triggering/loading principal rather than using the child-supplied aOrigin:

  nsCString derivedOrigin;
  nsCOMPtr<nsIPrincipal> principal = loadInfo->TriggeringPrincipal();
  principal->GetWebExposedOriginSerialization(derivedOrigin);
  ToLowerCase(derivedOrigin);
  // Use derivedOrigin instead of aOrigin
  rv = mChannel->AsyncOpenNative(uri, derivedOrigin,
      loadInfo->GetOriginAttributes(),  // from LoadInfo, not child
      aInnerWindowID, this, nullptr);

Similarly, aOriginAttributes should be taken from the reconstructed LoadInfo rather than trusted from the child.


Summary

The report identifies a real (if minor) defense-in-depth gap: the parent trusts the child's aOrigin string and aOriginAttributes without re-deriving them from the authenticated LoadInfo. However:

  • The PoC is entirely fabricated and non-functional
  • The vulnerability requires prior content process compromise to exploit
  • It does not represent a standalone security boundary violation
  • Severity: Low–Moderate (post-compromise enhancement only)

What is the practical impact of forging the Origin: header and private-browsing flag if this is exploited from a compromised content process?

Forging Origin: header

The Origin: header in WebSocket is the primary server-side CSRF defense — cookies provide the authentication, origin provides the authorization. Forging it enables:

Bypassing server-side origin allowlists. Many WebSocket services check that the connecting origin is one of a known set (e.g. wss://api.example only accepts connections from https://app.example). With origin forgery, a compromised process could make connections appear to come from any origin, bypassing those checks.

Important caveat: Cookies are sent based on the destination URL's cookie jar, not the forged Origin. So this does NOT let you steal victim.example's cookies — you can only make a connection to a server appear to originate from victim.example while carrying cookies for the actual destination. The value is in bypassing origin-based access control, not in cookie theft.

Compared to what a compromised renderer can already do: Fetch and XHR can already make credentialed requests — but those carry the real page origin in request headers.
Origin forgery lets you reach endpoints that check Origin: and would otherwise reject the real attacker-page origin.


Forging private-browsing OriginAttributes

This is the more interesting angle. Firefox isolates regular and private browsing cookie jars. A compromised regular-browsing content process cannot normally read private-browsing cookies.

With OriginAttributes forgery the attacker could instruct the parent to open a WebSocket using the private-browsing cookie jar while delivering the response back to the compromised regular-browsing process. If the user has an authenticated private-browsing session (e.g. to their bank or a second account on a service), those session cookies ride on the upgrade request, the server authenticates them, and the resulting WebSocket data flows back to the attacker.

This is a genuine cross-context isolation bypass — it violates the assumption that the two cookie jars are mutually inaccessible. The same works in reverse: private-browsing process correlating regular-browsing identity.


Overall assessment

  ┌───────────────────────┬───────────────────────────────────────────────────────────────┐
  │      Capability       │      Additional value over already-compromised renderer       │                                                                              
  ├───────────────────────┼───────────────────────────────────────────────────────────────┤
  │ Origin: forgery       │ Moderate — bypass origin-based access control on WS endpoints │                                                                              
  ├───────────────────────┼───────────────────────────────────────────────────────────────┤                             
  │ Private-browsing flip │ High — breaks the regular/private session isolation boundary  │
  └───────────────────────┴───────────────────────────────────────────────────────────────┘                                                                              

The private browsing angle is the most impactful piece. The rest is largely incremental on top of what a compromised content process can already accomplish.

Attached file (secure) —
Assignee: nobody → rjesup
Status: NEW → ASSIGNED

I'm not sure this would make sec-high given the impact and the requirement for a content compromise as well

Duplicate of this bug: 2031629

Comment on attachment 9569510 [details]
(secure)

Security Approval Request

  • How easily could an exploit be constructed based on the patch?: Unsure, but probably not super hard if you have a content exploit
  • Do comments in the patch, the check-in comment, or tests included in the patch paint a bulls-eye on the security problem?: No
  • Which branches (beta, release, and/or ESR) are affected by this flaw, and do the release status flags reflect this affected/unaffected state correctly?: all
  • If not all supported branches, which bug introduced the flaw?: None
  • Do you have backports for the affected branches?: No
  • If not, how different, hard to create, and risky will they be?: easy
  • How likely is this patch to cause regressions; how much testing does it need?: Very unlikely
  • Is the patch ready to land after security approval is given?: Yes
  • Is Android affected?: Yes
Attachment #9569510 - Flags: sec-approval?
Attachment #9569510 - Flags: sec-approval?

Tentative sec-low per discussion with Freddy

Keywords: sec-low
Pushed by rjesup@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/e2d11385d40f https://hg.mozilla.org/integration/autoland/rev/89b068c7bb00 Remove aOrigin & aOriginAttributes from WebSocket opens r=necko-reviewers,valentin
Pushed by smolnar@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/d84c5287cc1e https://hg.mozilla.org/integration/autoland/rev/7b83b4ba1377 Revert "Bug 2029339: Remove aOrigin & aOriginAttributes from WebSocket opens r=necko-reviewers,valentin" for causing bc failures @ browser_staticPartition_websocket.js

TEST-UNEXPECTED-FAIL | toolkit/components/antitracking/test/browser/browser_staticPartition_websocket.js | test_partitioned - Should have opened B

Flags: needinfo?(rjesup)
Pushed by rjesup@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/8bf40f9c44b2 https://hg.mozilla.org/integration/autoland/rev/071862510245 Remove aOrigin & aOriginAttributes from WebSocket opens r=necko-reviewers,valentin
Group: network-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 6 months ago
Resolution: --- → FIXED
Target Milestone: --- → 151 Branch

firefox-esr140 Uplift Approval Request

  • User impact if declined/Reason for urgency: Good defense in depth for esr
  • Code covered by automated testing?: no
  • Fix verified in Nightly?: yes
  • Needs manual QE testing?: no
  • Steps to reproduce for manual QE testing:
  • Risk associated with taking this patch: low
  • Explanation of risk level: pretty simple fix overall
  • String changes made/needed?: none
  • Is Android affected?: yes
Attachment #9571120 - Flags: approval-mozilla-esr140?
Flags: needinfo?(rjesup)
Attachment #9571120 - Flags: approval-mozilla-esr140? → approval-mozilla-esr140+
Whiteboard: [client-bounty-form][necko-triaged][necko-priority-queue] → [client-bounty-form][necko-triaged][necko-priority-queue][sec-adv-]

Our bounty program currently only considers "compromised content process" attacks for full sandbox escapes, not for site-isolation.

Flags: sec-bounty? → sec-bounty-
Whiteboard: [client-bounty-form][necko-triaged][necko-priority-queue][sec-adv-] → [client-bounty-form][necko-triaged][necko-priority-queue][adv-main151-][adv-esr140.11-]
QA Whiteboard: [sec] [qa-triage-done-c152/b151]
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: