Closed Bug 1980904 (CVE-2025-13017) Opened 1 year ago Closed 11 months ago

Same-site cross-origin iframes can request notification permission (and with wrong prompt on Android)

Categories

(Core :: DOM: Notifications, defect)

Firefox 141
defect

Tracking

()

RESOLVED FIXED
145 Branch
Tracking Status
firefox-esr115 --- unaffected
firefox-esr128 --- unaffected
firefox-esr140 145+ fixed
firefox141 --- wontfix
firefox142 --- wontfix
firefox143 --- wontfix
firefox144 --- wontfix
firefox145 + verified

People

(Reporter: apapedulimu, Assigned: saschanaz)

References

(Regression)

Details

(4 keywords, Whiteboard: [adv-main145+][adv-ESR140.5+])

Attachments

(6 files)

Attached video 2025-08-04 17-04-54.mp4 β€”

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36

Steps to reproduce:

  1. Go to https://dev.apapedulimu.click/index.php?url=https://long-domain-tester-accounts-subdo-tester-domain-accounts-google.comvulnerability.bug.apapedulimu.click/test.html
  2. Click "Request Notification" Button
  3. Observe the notification permission prompt that appears. You’ll notice that the prompt displays the top-level domain (dev.apapedulimu.click) as the source of the request β€” not the actual origin (*.google.comvulnerability.bug.apapedulimu.click) of the embedded iframe that triggered the request.

Actual results:

When a cross-origin iframe requests notification permission via Notification.requestPermission(), Firefox shows the top-level (main frame) origin in the permission prompt instead of the origin that actually initiated the request.
As a result, the user sees a trusted domain (e.g., dev.apapedulimu.click) requesting the permission, while in reality, the request originated from an embedded third-party domain (e.g., *.google.comvulnerability.bug.apapedulimu.click).

This allows an attacker to spoof the origin shown in the permission dialog, misleading users into granting notification access to an untrusted or malicious domain.

Expected results:

Browsers should show the actual origin making the request β€” in this case, (*.google.comvulnerability.bug.apapedulimu.click).

The prompt should display the origin of the requester (iframe), just like Firefox Desktop correctly does.

Summary: Notification permission origin spoofing → Notification permission origin spoofing on Android Firefox
Keywords: csectype-spoof
Summary: Notification permission origin spoofing on Android Firefox → Notification permission with long domain leads to spoof spoofing on Android Firefox

Hi Team,

I’d like to clarify that using a long URL is not necessary to reproduce this issue. By following the steps below, you’ll see that the notification request originates from dev.apapedulimu.click, as shown in the attached screenshot.

Steps to Reproduce:

  1. Open this URL:
    https://dev.apapedulimu.click/index.php?url=https://labs.apapedulimu.click/browser/notif.html
  2. Click Request Notification

Let me know if you need any additional details.

Best,
Nosa Shandy

Summary: Notification permission with long domain leads to spoof spoofing on Android Firefox → Notification permission spoofing on Android Firefox

Kagami: I think you're doing notification stuff. According to this testcase notifications are allowed to be requested by a framed site, in the framed-site's own name without having to do the permission-policy related "allow" attribute on the frame. Is that right? Seems very inconsistent with all the other permissions.

But the android behavior of showing the top-level domain would only be correct if there was "permission forwarding" via permission-policy allow so either way it looks broken on Android. Just not sure if it's broken on desktop also.

Flags: needinfo?(krosylight)

It's not supposed to open prompts at all, this is a regression 😬

Keywords: regression
Regressed by: 1914417
Group: mobile-core-security → core-security
Status: UNCONFIRMED → NEW
Component: General → DOM: Notifications
Ever confirmed: true
OS: Android → All
Product: Firefox for Android → Core
Group: core-security → dom-core-security

But I'm very confused about the test case. It seems Fission doesn't separate the processes between the parent and the iframe, even though they are cross origin? I see only one process for the tab when there should be two.

RequestPermission ends up thinking it's requested via a first party princpal and does not block the request.

navigator.storage.getDirectory() also gets the unpartitioned storage. I fear this is more than just notification.

Group: core-security
Component: DOM: Notifications → Privacy: Anti-Tracking
Flags: needinfo?(krosylight)
Summary: Notification permission spoofing on Android Firefox → Certain cross origin iframe doesn't get the partitioned storage key

(In reply to Kagami Rosylight [:saschanaz] (they/them) from comment #4)

But I'm very confused about the test case. It seems Fission doesn't separate the processes between the parent and the iframe, even though they are cross origin? I see only one process for the tab when there should be two.

They are different origins, but same-site, IIUC.

(Also the original test case is on Android which doesn't have Fission at all.)

Ah. TIL we don't partition for same sites.

Back to the missed question:

According to this testcase notifications are allowed to be requested by a framed site, in the framed-site's own name without having to do the permission-policy related "allow" attribute on the frame. Is that right? Seems very inconsistent with all the other permissions.

The intention is basically to not allow any third party permission request nor notifications.

Set release status flags based on info from the regressing bug 1914417

The new behavior doesn't match Chrome either, back to Notification.

(I wonder how severe this is if it's same site)

Component: Privacy: Anti-Tracking → DOM: Notifications
Summary: Certain cross origin iframe doesn't get the partitioned storage key → Same-site cross-origin iframes can request notification permission (and with wrong prompt on Android)
Group: core-security

(In reply to Nosa Shandy from comment #1)

notification request originates from dev.apapedulimu.click when iframing page from labs.apapedulimu.click

I’d like to clarify that using a long URL is not necessary to reproduce this issue. By following the steps below, you’ll see that the notification request originates from dev.apapedulimu.click, as shown in the attached screenshot.

Yes, the underlying problem is not about URL truncation or spoofing.

Years ago most folks working on browsers realized that cross-origin iframes requesting a permission was inherently spoofy. Even if the permission dialog says the real origin name, many users are likely to assume it's the top-level site asking because that's the only URL they see associated with the page. So we ended up with Permissions Policy, where cross-origin frames can only use a permission if the top-level page explicitly delegates its to the iframe. And when it has, the prompt the user sees shows the name of the top-level site, because that is the site that will get the permission (if the user saves it). If granted, the framed site can now use the permission because it's delegated.

The Notification API isn't part of the Permission-Policy model. Years ago Chromium and Firefox agreed it should be restricted to same-origin frames only. Safari, however, still has the original behavior of asking for the permission in the name of the framed site. That restriction was broken (by bug 1914417 according to Kagami) and Firefox desktop reverted to its old Safari-matching behavior.

The newer Firefox for Android front end never had to deal with notifications as a special case, so it apparently assumes any permission request must be following the Permission-Policy inheritance model. If there are any other non-standard permissions that could still be a problem after this Notification API regression is fixed. It may mean that the GeckoView layer is not forwarding the requesting origin to the front-end.

The permission seems to be saved with the domain shown in the prompt. On Desktop the permissions is granted to https://long-domain-tester-accounts-subdo-tester-domain-accounts-google.comvulnerability.bug.apapedulimu.click, and you can go there by itself and see that it works. On Android the permission is not granted to the subdomain and visiting that on its own does not have a remembered permission, but it acts as if dev.apapedulimu.click has a remembered delegated permission

Thanks so much for the clarification Daniel Veditz, really appreciate the detailed response!

Just to confirm:
Will this be considered a security vulnerability, since it allows cross-origin iframes to trigger permission prompts (which shouldn’t be allowed)? Or is it being tracked as a functionality issue?

Either way, I’m looking forward to the next update. Let me know if I can help retest anything as things move forward!

Flags: sec-bounty?

Kagami, could you please assign a severity?

Flags: needinfo?(krosylight)

I'm confused by the lack of sec tag at all now, and my question in comment #10 still applies.

Set release status flags based on info from the regressing bug 1914417

re: question in comment 10: -- yes, it's "less bad" that it's not full cross-origin, but it's still wrong.

I assume we'll want to backport bug 1988751 to Beta & ESR140? Please nominate if yes.

Group: dom-core-security → core-security-release
Status: NEW → RESOLVED
Closed: 11 months ago
Flags: needinfo?(krosylight)
Resolution: --- → FIXED
Target Milestone: --- → 145 Branch
Flags: needinfo?(krosylight)
QA Whiteboard: [sec] [uplift] [qa-ver-needed-c145/b144]
Flags: qe-verify+

Err, it's actually not ABA, it's AA...

Status: RESOLVED → REOPENED
Resolution: FIXED → ---
QA Contact: cgeorgiu

The bug is marked as tracked for firefox144 (beta) and tracked for firefox145 (nightly). However, the bug still has low severity.

:hsinyi, could you please increase the severity for this tracked bug? If you disagree with the tracking decision, please talk with the release managers.

For more information, please visit BugBot documentation.

Flags: needinfo?(htsai)
Severity: S3 → S2
Flags: needinfo?(htsai)
Pushed by agoloman@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/c7c08652632a https://hg.mozilla.org/integration/autoland/rev/2e1ae3d82bb7 Revert "Bug 1980904 - Deny notification requests for all cross origins r=asuth" for causing mochitest failures @test_notification_crossorigin_iframe.html.

Backed out for causing mochitest failures @test_notification_crossorigin_iframe.html.

Flags: needinfo?(krosylight)
Status: REOPENED → RESOLVED
Closed: 11 months ago11 months ago
Resolution: --- → FIXED
Target Milestone: --- → 145 Branch

firefox-esr140 Uplift Approval Request

  • User impact if declined: Misleading permission prompt with different domain
  • Code covered by automated testing: yes
  • Fix verified in Nightly: yes
  • Needs manual QE test: no
  • Steps to reproduce for manual QE testing:
  • Risk associated with taking this patch: low
  • Explanation of risk level: Reverting to the previous behavior
  • String changes made/needed: N/A
  • Is Android affected?: yes
Attachment #9518976 - Flags: approval-mozilla-esr140?

I was able to repro this issue using an affected Nightly build (2025-08-04) with STR from comment 1 on Win 11.

The issue is verified as fixed on latest Nightly 145.0a1 under Win 11, macOS 15 and Ubuntu 24.

QA Whiteboard: [sec] [uplift] [qa-ver-needed-c145/b144] → [sec] [uplift] [qa-ver-done-c145/b144]
Flags: qe-verify+
Flags: sec-bounty? → sec-bounty+
Attachment #9518976 - Flags: approval-mozilla-esr140? → approval-mozilla-esr140+
Whiteboard: [adv-main145+][adv-ESR140.5+]
Attached file advisory.txt β€”
Alias: CVE-2025-13017
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: