PSerialManager IPC bypasses dom.webserial.enabled pref and the Serial API permission flow
Categories
(Core :: DOM: Web Serial, defect)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox-esr115 | --- | unaffected |
| firefox-esr140 | --- | unaffected |
| firefox149 | --- | unaffected |
| firefox150 | --- | unaffected |
| firefox151 | + | fixed |
| firefox152 | + | fixed |
People
(Reporter: pakhunov.anton.n, Assigned: gstoll)
References
(Regression)
Details
(5 keywords)
Attachments
(2 files, 1 obsolete file)
|
48 bytes,
text/x-phabricator-request
|
Details | Review | |
|
48 bytes,
text/x-phabricator-request
|
phab-bot
:
approval-mozilla-beta+
|
Details | Review |
I was reviewing the pattern from bug 2032622 (DOMFullscreenParent trusting
child-supplied pref-gated state) and noticed Web Serial has a much sharper
version of the same problem. The pref dom.webserial.enabled defaults to
false on all release channels (StaticPrefList.yaml). The pref is the only
thing keeping Web Serial off in release builds.
Pref enforcement lives entirely on the child side:
dom/webidl/Serial.webidl:23
[SecureContext, Pref="dom.webserial.enabled", Exposed=(Window,DedicatedWorker)]
dom/webserial/Serial.cpp
Serial.requestPort / Serial.getPorts go through PortSecurityCheck and
the SerialPermissionRequest UI flow.
Both gates only apply to the WebIDL-bound JS API. Underneath that, the
PSerialManager protocol is exposed through PWindowGlobal:
dom/ipc/PWindowGlobal.ipdl:238
async PSerialManager();
The parent constructor in WindowGlobalParent has no pref check and no
permission check:
dom/ipc/WindowGlobalParent.cpp:1880-1890
already_AddRefed<PSerialManagerParent>
WindowGlobalParent::AllocPSerialManagerParent() {
return MakeAndAddRef<SerialManagerParent>();
}
mozilla::ipc::IPCResult WindowGlobalParent::RecvPSerialManagerConstructor(
PSerialManagerParent* aActor) {
auto* manager = static_cast<SerialManagerParent*>(aActor);
manager->Init(BrowsingContext()->GetBrowserId());
return IPC_OK();
}
Once the actor is up:
-
SerialManagerParent::RecvGetAvailablePorts calls
platformService->EnumeratePorts and returns every serial device visible
to the host. No permission check, no pref check. The platform service
is a singleton that initializes unconditionally in
SerialPlatformService::GetInstance regardless of the pref (it only
consults the testing pref to choose between real and
TestSerialPlatformService backends). -
SerialManagerParent::RecvCreatePort instantiates a SerialPortParent
for any portId the child names. There is no check that this
(origin, portId) pair was ever permitted by the user. -
SerialPortParent::RecvOpen opens the physical port through the
platform service. The only validation is on bufferSize and the
already-opened state; no permission verification.
Attack path:
- Attacker has code execution in a content process (separate sec-high
precondition). - From the compromised renderer, reach WindowGlobalChild and call
wgc.sendPSerialManagerConstructor(child) directly. The WebIDL gate is
skipped entirely. The pref is not checked parent-side. - SendGetAvailablePorts. Attacker enumerates every USB-serial device
the user has plugged in: vendorId, productId, port path. Useful for
reconnaissance and for fingerprinting (some adapters expose serial
numbers). - Pick any portId from the list. SendCreatePort(portId, endpoint).
SerialPortParent is constructed for that physical device. - SendOpen(IPCSerialOptions{...}). Port is physically opened.
- The attacker now has arbitrary read and write access to whatever
device is on that port: Arduino-class microcontrollers (flash and
run firmware), industrial control devices, point-of-sale equipment,
hardware security tokens that expose serial endpoints, embedded
system debug ports, USB-to-serial cables connected to other
machines, and so on.
The bypass takes out both layers of defense:
(a) the release-off dom.webserial.enabled pref that is intended to
keep the entire feature dormant on release / beta / ESR,
(b) the SerialPermissionRequest user-consent dialog flow that is
the web spec's entire security model for Web Serial.
Suggested fix, mirroring bug 2032622: gate at the parent IPC handler.
mozilla::ipc::IPCResult WindowGlobalParent::RecvPSerialManagerConstructor(
PSerialManagerParent* aActor) {
if (!StaticPrefs::dom_webserial_enabled()) {
return IPC_FAIL(this, "Web Serial disabled by pref");
}
auto* manager = static_cast<SerialManagerParent*>(aActor);
manager->Init(BrowsingContext()->GetBrowserId());
return IPC_OK();
}
That blocks actor creation when the pref is off. Per-port permission
enforcement is a separate fix that should land on top of this one:
SerialManagerParent::RecvCreatePort and SerialPortParent::RecvOpen
should look up the permission database for the (origin, portId) pair
the actor claims, instead of trusting the renderer to have already
asked the user.
Bugzilla dedupe: searched DOM: Device Interfaces (core-security and
public) and nine keyword combinations covering Web Serial pref bypass,
permission bypass, and SerialManagerParent topics. Zero prior hits on
this specific bypass. Bug 2031173 added an enterprise policy gate but
that gate is also pref-based and is bypassed by the same handler gap.
Bug 2030195 and 2029008 are about add-on permission gating, which is
a separate concern.
Verified on mozilla-central tip via hg-edge raw-file of
dom/ipc/WindowGlobalParent.cpp. AllocPSerialManagerParent and
RecvPSerialManagerConstructor are unchanged from the local clone
version: no pref or permission check is added.
Updated•4 months ago
|
Updated•4 months ago
|
Updated•4 months ago
|
Comment 1•4 months ago
|
||
:gstoll, since you are the author of the regressor, bug 2010930, could you take a look? Also, could you set the severity field?
For more information, please visit BugBot documentation.
Comment 2•4 months ago
|
||
This sounds not great. I'm not sure how bad it is exactly to be able to start accessing devices, but I guess in the worst case it is like a sandbox escape.
Comment 3•4 months ago
|
||
[Tracking Requested - why for this release]: Possibly bad security regression. I think we should be sure to at least not ship the basic permission part here, as that is hopefully easy to fix. (The async nature of pref setting can make it annoying to get tests working sometimes.)
| Assignee | ||
Comment 4•4 months ago
|
||
We can certainly fix the pref problem (although we're about to toggle this on for everyone in bug 2029625).
The other part is trickier. I looked into this during development, and IIRC ContentPermissionRequestBase (the base class of SerialPermissionRequest) is designed to be used from the content process. Although surely other subclasses of ContentPermissionRequestBase don't have this problem?
Updated•4 months ago
|
Comment 5•4 months ago
|
||
The bug has a release status flag that shows some version of Firefox is affected, thus it will be considered confirmed.
Comment 6•4 months ago
|
||
The bug is marked as tracked for firefox151 (nightly). However, the bug still isn't assigned.
:jstutte, could you please find an assignee for this tracked bug? Given that it is a regression and we know the cause, we could also simply backout the regressor. If you disagree with the tracking decision, please talk with the release managers.
For more information, please visit BugBot documentation.
Updated•4 months ago
|
Updated•4 months ago
|
| Assignee | ||
Comment 7•4 months ago
|
||
OK, we can do this, we just have to implement nsIContentPermissionRequest instead of using the base class.
| Assignee | ||
Comment 8•4 months ago
|
||
Comment 9•4 months ago
|
||
Set release status flags based on info from the regressing bug 2010930
Comment 10•4 months ago
|
||
If you could get around the permission flow from web content this would be a sec-high privilege escalation, but it requires a compromised content process as a pre-condition which lowers the risk (but not the impact).
Updated•4 months ago
|
| Assignee | ||
Updated•4 months ago
|
Comment 11•4 months ago
|
||
firefox-beta Uplift Approval Request
- User impact if declined/Reason for urgency: sec bug that affects WebSerial in beta
- Code covered by automated testing?: yes
- Fix verified in Nightly?: no
- Needs manual QE testing?: no
- Steps to reproduce for manual QE testing: n/a
- Risk associated with taking this patch: low
- Explanation of risk level: reworking some IPC stuff, but we have pretty good test coverage around this
- String changes made/needed?: no
- Is Android affected?: no
| Assignee | ||
Comment 12•4 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D295054
Comment 13•4 months ago
|
||
Comment 14•4 months ago
|
||
Comment 15•4 months ago
|
||
dom/webserial/Serial.cpp:X:21: error: enumeration value 'EndGuard_' not handled in switch [-Werror,-Wswitch]
Comment 16•4 months ago
|
||
Comment 17•4 months ago
|
||
Comment 18•4 months ago
|
||
[task 2026-04-27T23:55:12.013+00:00] 23:55:12 INFO - gmake[4]: Leaving directory '/builds/worker/workspace/obj-build/toolkit/library/build'
[task 2026-04-27T23:55:12.013+00:00] 23:55:12 ERROR - ld.lld: error: undefined hidden symbol: mozilla::dom::SerialPermissionRequest::GetIgnoreAllowSitePermission(bool*)
[task 2026-04-27T23:55:12.013+00:00] 23:55:12 INFO - >>> referenced by Unified_cpp_dom_webserial0.cpp
[task 2026-04-27T23:55:12.013+00:00] 23:55:12 INFO - >>> ../../../dom/webserial/Unified_cpp_dom_webserial0.o:(vtable for mozilla::dom::SerialPermissionRequest)
Comment 19•4 months ago
|
||
| Assignee | ||
Updated•4 months ago
|
Comment 20•4 months ago
|
||
Comment 21•4 months ago
|
||
Backed out for causing build bustages at SerialManagerParent
Backout Link
Push with failures
Failure Log
Failure line /builds/worker/checkouts/gecko/dom/webserial/SerialManagerParent.cpp:X:10: error: incomplete type 'mozilla::dom::Serial' named in nested name specifier
Comment 22•4 months ago
|
||
Comment 23•4 months ago
|
||
Comment 24•4 months ago
|
||
Comment 25•4 months ago
|
||
Updated•4 months ago
|
Comment 26•4 months ago
|
||
firefox-beta Uplift Approval Request
- User impact if declined/Reason for urgency: sec bug that affects WebSerial in beta
- Code covered by automated testing?: yes
- Fix verified in Nightly?: no
- Needs manual QE testing?: no
- Steps to reproduce for manual QE testing: n/a
- Risk associated with taking this patch: low
- Explanation of risk level: reworking some IPC stuff, but we have pretty good test coverage around this
- String changes made/needed?: no
- Is Android affected?: no
| Assignee | ||
Comment 27•4 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D295054
Updated•4 months ago
|
Updated•4 months ago
|
Comment 28•4 months ago
|
||
| uplift | ||
Updated•4 months ago
|
| Reporter | ||
Comment 29•3 months ago
|
||
Hi Daniel, the fix landed on 2026-04-28 with beta uplift on 2026-04-30. Any rough idea where this sits in the bounty review queue? No urgency, just trying to calibrate expectations. Thanks.
Comment 30•2 months ago
|
||
(In reply to pakhunov.anton.n from comment #29)
Hi Daniel, the fix landed on 2026-04-28 with beta uplift on 2026-04-30. Any rough idea where this sits in the bounty review queue? No urgency, just trying to calibrate expectations. Thanks.
Currently it sits nowhere because you did not submit it to our bounty program. I am doing so now for this bug but for the future please see https://www.mozilla.org/en-US/security/client-bug-bounty/#claiming-a-bounty
Please generally keep bug bounty related questions out of the bug and instead email us at the address in that document. The developers working on bugs are uninterested in bounty conversations and can't give any authoritative answers. Email us instead.
Updated•1 month ago
|
Updated•1 month ago
|
Updated•1 month ago
|
Comment 31•1 month ago
|
||
We don't believe this is eligible for a bounty. Yes, it gets around a permission check, but it requires a compromised process and isn't a sandbox-escape, and it also would require the victim to have a web serial device attached, and for that device to have a known vulnerability you can then exploit.
Updated•12 days ago
|
Description
•