Closed Bug 2038558 Opened 2 months ago Closed 2 months ago

ContentParent::RecvAddCertException accepts arbitrary host/cert override requests from content, enabling permanent certificate-validity overrides for any host after content-process compromise

Categories

(Core :: DOM: Content Processes, defect)

defect

Tracking

()

RESOLVED DUPLICATE of bug 2013800

People

(Reporter: cs.attila, Unassigned)

References

()

Details

(Keywords: ai-involved, reporter-external, Whiteboard: [client-bounty-form])

Attachments

(1 file)

Summary

ContentParent::RecvAddCertException appears to accept a content-supplied hostname, port, origin attributes, certificate, and temporary/permanent flag and forwards them to nsCertOverrideService::RememberValidityOverride(...) without verifying that the sending content process is allowed to add a certificate-validity override for that hostname.

A compromised content process can therefore attempt to install a certificate-validity override for an arbitrary host, with an attacker-supplied certificate, without going through the visible about:certerror / “Accept the Risk and Continue” user-confirmation flow for that host.

This is not a normal web-content JavaScript-only attack and is not a sandbox escape. The precondition is a compromised content process / renderer-RCE-capable primitive that can send raw PContent IPC. Exploitation of the installed override for traffic compromise also requires a network MITM position for the targeted host.

Affected path

Primary path:

  • dom/ipc/PContent.ipdl
    • async AddCertException(nullable nsIX509Cert aCert, nsCString aHostName, int32_t aPort, OriginAttributes aOriginAttributes, bool aIsTemporary)
  • dom/ipc/ContentParent.cpp
    • ContentParent::RecvAddCertException(...)
  • security/manager/ssl/nsCertOverrideService.cpp
    • nsCertOverrideService::RememberValidityOverride(...)
    • nsCertOverrideService::AddEntryToList(...)

Legitimate UI path:

  • dom/base/Document.cpp
    • Document::AddCertException(...)
  • toolkit/content/aboutNetError.mjs / net-error-card.mjs
    • visible user action on the certificate-error page

Missing validation

The intended invariant appears to be:

A request to install a certificate-validity override for a host must be bound to a deliberate user action on the certificate-error UI for that exact host, and to the content process / browsing context that is displaying that host’s certificate error.

The observed parent-side path appears to trust the content-supplied aHostName directly:

ContentParent::RecvAddCertException(..., nsCString aHostName, int32_t aPort,
                                    OriginAttributes aOriginAttributes,
                                    nsIX509Cert* aCert, bool aIsTemporary, ...)
{
  nsCOMPtr<nsICertOverrideService> overrideService =
      do_GetService(NS_CERTOVERRIDE_CONTRACTID);
  ...
  nsresult rv = overrideService->RememberValidityOverride(
      aHostName, aPort, aOriginAttributes, aCert, aIsTemporary);
  ...
}

RememberValidityOverride(...) appears to validate argument shape — non-empty ASCII hostname, valid port, non-null certificate, main-thread execution — then stores an override keyed by the supplied host/port/origin attributes and certificate fingerprint. I do not see a check that ties aHostName to the sending content process, the browsing context that encountered a certificate error, or a parent-authoritative failed channel/load.

Attack sketch

Precondition:

The attacker has compromised a content process and can send raw PContent IPC. To turn the installed override into traffic compromise, the attacker must also be able to MITM the user’s connection to the targeted host.

Steps:

  1. The attacker creates or obtains an nsIX509Cert for an attacker-controlled certificate.

  2. From the compromised content process, the attacker sends a raw AddCertException IPC similar to:

SendAddCertException(attackerCert,
                     "victim.example"_ns,
                     443,
                     OriginAttributes{},
                     /* aIsTemporary = */ false)
  1. The parent calls nsCertOverrideService::RememberValidityOverride(...) and installs a certificate-validity override for (victim.example, 443, originAttributes, sha256(attackerCert)).

  2. Later, when Firefox connects to https://victim.example, an attacker with a network MITM position presents attackerCert.

  3. The certificate validation failure that would normally be fatal now matches the stored override, so Firefox accepts the connection. The attacker can then decrypt or modify the targeted host’s TLS traffic.

The attacker can repeat this for multiple hostnames. The key issue is that the override host is content-supplied and not proven to be the host for which the user clicked the certificate-error UI.

Claimed impact

A compromised content process can pre-install a certificate-validity override for an arbitrary host without user confirmation for that host.

With an additional network MITM position, this can disable TLS certificate validation for the targeted host and enable full MITM of that host’s traffic using the attacker-supplied certificate.

Important limitations:

  • This is not a normal JavaScript-only web exploit.
  • This requires a compromised content process or equivalent raw-IPC primitive.
  • This is not a sandbox escape.
  • Actual TLS traffic compromise additionally requires a network MITM position.
  • I have not attached a standalone renderer-RCE PoC; the proof is source-level analysis of the parent-side IPC validation gap.

Why this looks like a missing validation

The legitimate flow is a host-specific certificate-error UI decision. The parent-side IPC path appears to accept the host directly from the child process and store the override without verifying that the request is tied to a certificate-error page / failed load for that host.

That makes the request identity (aHostName) attacker-controlled under a compromised-content-process model.

Suggested fix

Suggested shape:

  1. Do not allow arbitrary content processes to install certificate overrides for arbitrary hostnames.

  2. Bind the override request to a parent-authoritative failed TLS channel/load or a BrowsingContext / WindowContext that is known to be displaying the certificate-error page for that exact hostname.

  3. In ContentParent::RecvAddCertException(...), verify that:

    • the sending content process owns the relevant browsing context;
    • the failed-load hostname matches aHostName;
    • the user action occurred in the certificate-error UI for that load;
    • the supplied certificate matches the failed certificate for that load.
  4. Consider rejecting aIsTemporary=false unless the request is provably tied to the visible “Accept the Risk” UI and the exact failed host.

  5. Alternatively, move override installation entirely off this generic content-process IPC path and perform it through a parent-process actor bound to the failed channel/load.

Reporter notes

I am reporting this privately as a security-sensitive bug.

I am not claiming exploitation in the wild.

I am not claiming a standalone sandbox escape.

I can help develop a targeted Mozilla test / IPC-level reproducer if the team can confirm the preferred harness style for exercising PContent::AddCertException from a compromised-content-process model.

Flags: sec-bounty?
Group: firefox-core-security
Status: UNCONFIRMED → RESOLVED
Closed: 2 months ago
Component: Security → DOM: Content Processes
Duplicate of bug: CVE-2026-16372
Keywords: ai-involved
Product: Firefox → Core
Resolution: --- → DUPLICATE
Flags: sec-bounty? → sec-bounty-
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: