Closed Bug 2010743 (CVE-2026-2782) Opened 9 months ago Closed 9 months ago

Prototype Pollution in RequestPanel.js getProperties()

Categories

(DevTools :: Netmonitor, defect, P2)

Firefox 147
defect

Tracking

(firefox-esr115 wontfix, firefox-esr140148+ fixed, firefox147 wontfix, firefox148+ fixed, firefox149+ fixed)

RESOLVED FIXED
149 Branch
Tracking Status
firefox-esr115 --- wontfix
firefox-esr140 148+ fixed
firefox147 --- wontfix
firefox148 + fixed
firefox149 + fixed

People

(Reporter: cy1yang, Assigned: bomsy)

References

Details

(Keywords: csectype-priv-escalation, reporter-external, sec-moderate, Whiteboard: [adv-main148+] [adv-esr140.8+])

Attachments

(1 file, 3 external files, 1 obsolete file)

Attached file poc.html โ€”

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36

Steps to reproduce:

Reproduce

  • Open the poc.html with FireFox
  • Open Firefox DevTools (F12)
  • Navigate to the Network tab
  • Click one of the test buttons (e.g., "Test 1: proto Parameter")
  • In the Network Monitor, click on the POST request that appears
  • Click on the "Request" tab/panel to view form data

Actual results:

The Network panel crashes with a TypeError:

The Network panel has crashed.
File Bug Report
TypeError: map[obj.name].push is not a function
React Component Stack

in RequestPanel

in Connect(RequestPanel)

in div

in TabPanel
...

Stacktrace

getProperties/<@resource://devtools/client/netmonitor/src/components/request-details/RequestPanel.js:145:23

getProperties@resource://devtools/client/netmonitor/src/components/request-details/RequestPanel.js:139:16

render@resource://devtools/client/netmonitor/src/components/request-details/RequestPanel.js:211:22
...

Close and reopen the toolbox to clear this error.

Expected results:

Analysis

The getProperties() method at lines 138-150 uses a plain object literal {} as the reduce accumulator. When a form parameter has name __proto__:

  1. map["__proto__"] returns Object.prototype (not undefined)
  2. Object.prototype passes the check if (value || value === "")
  3. Code tries to call Object.prototype.push() โ†’ TypeError crash

Affected Code

Location: RequestPanel.js:138-150

getProperties(arr) {
    return arr.reduce((map, obj) => {
        const value = map[obj.name];
        if (value || value === "") {
            if (typeof value !== "object") {
                map[obj.name] = [value];
            }
            map[obj.name].push(obj.value);  // โ† CRASH when obj.name = "__proto__"
        } else {
            map[obj.name] = obj.value;
        }
        return map;
    }, {});  // โ† BUG: Should be Object.create(null)
}

Trigger location: RequestPanel.js:211

this.getProperties(parseFormData(sections))

Expected results

The code should use Object.create(null) instead of {} as the reduce accumulator, preventing prototype chain lookups:

return arr.reduce((map, obj) => {
    // ... same logic ...
}, Object.create(null));  // โ† FIX: null-prototype object

This is exactly how the same vulnerability was fixed in:

  • UrlPreview.js line 228 (bug 1801542, commit ccc6e2a65496)
  • CookiesPanel.js line 111

The testcase creates a request with a fetch call where the body is set to __proto__=evil_value&normal=test. Devtools then apparently parses that and assigns the key/value pairs into an object.

A more thorough fix here would be to use a Map rather than a plain object as an accumulator, so that there isn't a magic __proto__ key in the first place - or perhaps we can even use URLSearchParams or Form or something else builtin to do this parsing for us?

I also wonder if there is a way to opt the devtools env in which this code runs into the system principal environment where we just don't allow modifying the object prototype. Jan, do you know?

Component: Untriaged → Netmonitor
Flags: needinfo?(jdemooij)
Product: Firefox → DevTools
See Also: → CVE-2023-25731

(In reply to :Gijs (he/him) from comment #1)

I also wonder if there is a way to opt the devtools env in which this code runs into the system principal environment where we just don't allow modifying the object prototype. Jan, do you know?

We have the setFreezeBuiltins(true) option for RealmCreationOptions to freeze/seal (some) builtin objects to make it harder to take advantage of prototype pollution. This flag is set in mozJSModuleLoader::CreateLoaderGlobal and the if-statement there suggests this already happens for the DevTools loader, but I don't know if that loader is used for the JS code executed here:

  creationOptions.setFreezeBuiltins(true) <snip>
  if (IsDevToolsLoader()) {
    ...

This wouldn't prevent the bug here though because we don't modify any prototypes, we just try to call Object.prototype.push and this property doesn't exist so we throw an exception.

Flags: needinfo?(jdemooij)

The loader where IsDevToolsLoader()==true is the one used to load DevTools backend, but only when using the browser toolbox.

Here, the netmonitor code involved is executed from an iframe document's global (netmonitor/index.html). Can we freeze builtins for a document?
Note that I wouldn't be surprised if some of the frontend deps (react, redux,...) are modifying the builtins :/

Attached file (secure) โ€”
Assignee: nobody → hmanilla
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true

Gijs, should this still be a security bug, it seems to lead to a crash ? If yes, should it be sec-low, similar as https://bugzilla.mozilla.org/show_bug.cgi?id=1801542 ?

Flags: needinfo?(gijskruitbosch+bugs)
Severity: -- → S3
Priority: -- → P2

(In reply to Alexandre Poirot [:ochameau] from comment #3)

The loader where IsDevToolsLoader()==true is the one used to load DevTools backend, but only when using the browser toolbox.

Here, the netmonitor code involved is executed from an iframe document's global (netmonitor/index.html). Can we freeze builtins for a document?

I don't see an API for windows/documents looking at the reference in comment #2 but I assume we already do this for browser windows so I figure it must be possible - but perhaps it's hardcoded for system principal windows or I'm misremembering - Jan?

Note that I wouldn't be surprised if some of the frontend deps (react, redux,...) are modifying the builtins :/

I don't think react and redux will (they're new enough to be from a time when we all agreed that doing this is bad, I would have thought?), but it's possible other things do. Anyway, trying is the only way to be sure.

(In reply to Julian Descottes [:jdescottes] from comment #5)

Gijs, should this still be a security bug, it seems to lead to a crash ? If yes, should it be sec-low, similar as https://bugzilla.mozilla.org/show_bug.cgi?id=1801542 ?

I'm unclear on what we mean by "crash" here; I can't easily safely test this right now. The way I read comment 0 actually made me think this was running into a JS exception, not a "real" crash. I also don't know that we're confident that a more severe outcome is not possible. It's now been marked as sec-moderate . Even if a more severe outcome was not possible, just the "crash" (real or exception-based) could still be a DoS type vulnerability, which we still treat as sec bug (though often sec-low instead of sec-moderate).

Flags: needinfo?(gijskruitbosch+bugs) → needinfo?(jdemooij)

(In reply to :Gijs (he/him) from comment #6)

I don't see an API for windows/documents looking at the reference in comment #2 but I assume we already do this for browser windows so I figure it must be possible - but perhaps it's hardcoded for system principal windows or I'm misremembering - Jan?

We tried to enable this for system principal windows but it caused test failures so in the end we only did it for the shared system global (bug 1771084 comment 17).

I just pushed that change to try again and there is a lot of orange, especially in DevTools tests:

https://treeherder.mozilla.org/jobs?repo=try&group_state=expanded&revision=d67481fb016a77db6fda7bbc1c2f3625706c4442

Flags: needinfo?(jdemooij)
Pushed by hmanilla@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/9fd39d416d93 https://hg.mozilla.org/integration/autoland/rev/97d938363c93 [devtools] Avoid prototype pollution when parsing form data r=devtools-reviewers,nchevobbe
Group: firefox-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 9 months ago
Resolution: --- → FIXED
Target Milestone: --- → 149 Branch

:bomsy, adding a need info for uplift requests.
I'm not sure if this is needed on esr115/esr140. It will need a rebase if needed on the ESR branches.

Attached file (secure) (obsolete) โ€”

Highlights of this patch

  • Use Object.create(null) instead of {} when mapping the format data sections array to a array of dictionaries.
  • Use URLSearchParams to parse the format-data sections
  • Added tests to assert the fix for the prototype pollution.

Original Revision: https://phabricator.services.mozilla.com/D279525

Attachment #9542348 - Flags: approval-mozilla-esr115?
Attached file (secure) โ€”

Highlights of this patch

  • Use Object.create(null) instead of {} when mapping the format data sections array to a array of dictionaries.
  • Use URLSearchParams to parse the format-data sections
  • Added tests to assert the fix for the prototype pollution.

Original Revision: https://phabricator.services.mozilla.com/D279525

Attachment #9542350 - Flags: approval-mozilla-esr140?

:bomsy, you might already be working through it but to call out:

  • This will need a beta uplift request
  • The uplift request needs an uplift request form for review

firefox-beta Uplift Approval Request

  • User impact if declined: Might crash developer tools for users
  • 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: Low risk. Medium size JS patch to fix and refactor the code.
  • String changes made/needed: None
  • Is Android affected?: no
Attachment #9542675 - Flags: approval-mozilla-beta?
Attached file (secure) โ€”

Highlights of this patch

  • Use Object.create(null) instead of {} when mapping the format data sections array to a array of dictionaries.
  • Use URLSearchParams to parse the format-data sections
  • Added tests to assert the fix for the prototype pollution.

Original Revision: https://phabricator.services.mozilla.com/D279525

Flags: needinfo?(hmanilla)
Attachment #9542675 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
QA Whiteboard: [sec] [uplift] [qa-triage-done-c149/b148]
Attachment #9542350 - Flags: approval-mozilla-esr140? → approval-mozilla-esr140+
Attachment #9542348 - Flags: approval-mozilla-esr115? → approval-mozilla-esr115+

Backed out of ESR115 for causing test failures
ESR115 is eol in the next release, so setting it to wontfix instead.

Attachment #9542348 - Attachment is obsolete: true
Whiteboard: [adv-main148+]
Whiteboard: [adv-main148+] → [adv-main148+] [adv-esr140.8+]
Alias: CVE-2026-2782
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: