Firefox · DOM
CVE-2026-117968
UAF in DOM
Overview
Moderate
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Background
- `HTMLFormElement::SubmitSubmission`
- The method in
dom/html/HTMLFormElement.cppthat carries out a form submission after the submission object has been built, locating the docshell/link handler that will actually perform the navigation. - `GetComposedDoc()`
- Returns a raw
Document*for the element’s composed document (null if the element is not in a composed document). Ownership stays with the DOM; the returned pointer must not be held across operations that can drop the document. - `RefPtr<Document>`
- A strong reference to a
Document; holding it prevents the document from being destroyed while the pointer is in scope. - `nsDocShell` / link handler
- The submission needs the document’s docshell (
doc->GetDocShell()) to find a container able to perform the navigation;IsEditable()and other checks follow. - Re-entrancy during submission
- Form submission can fire events / run script (e.g.
formdata/submithandlers already dispatched, mutation, navigation side effects) that can tear down the document mid-method.
Root Cause Analysis
The one-line fix changes
Document* doc = GetComposedDoc(); to RefPtr<Document> doc = GetComposedDoc(); in HTMLFormElement::SubmitSubmission. Pre-fix, the composed document was captured as a raw Document* and then used to obtain the docshell: RefPtr<nsDocShell> container = doc ? nsDocShell::Cast(doc->GetDocShell()) : nullptr;. Between capturing the raw doc and dereferencing it, form-submission machinery can run script or otherwise re-enter in a way that releases the last strong reference to the document, freeing it. The subsequent doc->GetDocShell() would then dereference freed memory — a use-after-free of the Document. By holding the document in a RefPtr<Document>, the patch guarantees the document outlives its use within the method, closing the window where it could be freed out from under the raw pointer. The change is a textbook Gecko lifetime fix: the invariant “a DOM object used across potentially re-entrant/script-running work must be held by a strong reference” was violated by using a bare Document*. The advisory’s “use-after-free in DOM: Core & HTML” matches the diff exactly.Key insight
SubmitSubmission held the composed document in a raw Document* while form-submission work could run script and drop the document’s last reference; dereferencing that pointer to fetch the docshell was a use-after-free, fixed by taking a RefPtr<Document>.Attack Path
- Script-triggered submission
Page script calls
form.submit()/requestSubmit()or otherwise drives a submission that reachesHTMLFormElement::SubmitSubmission(web-reachable via ordinary form APIs). - Arrange document teardown Register a handler or arrange mutation reachable during the submission flow that detaches/destroys the form’s composed document (e.g. removing the containing browsing context/document mid-submit).
- Capture raw `doc`
Pre-fix,
SubmitSubmissionstores the composed document asDocument* doc. - Free the document The re-entrant work releases the last reference to that document, freeing it.
- Use freed document
doc->GetDocShell()dereferences the freedDocument. - Primitive achieved
Use-after-free of a
Documentobject; with heap grooming the freed allocation could be reclaimed with attacker-controlled data (escalation inferred, not shown by the diff).
Impact Assessment
This runs in the content/renderer process and is reachable from ordinary web content via form-submission APIs, requiring no special privilege. The primitive is a use-after-free of a
Document, reached during submission when script can run and drop the document. The diff proves the lifetime bug (raw pointer → RefPtr) but does not demonstrate a working exploit primitive beyond the dangling dereference; escalation to code execution would require controlling the freed allocation (inferred). Mozilla rates it moderate.Files Changed
dom/html/HTMLFormElement.cpp
Audit Directions
- Raw `GetComposedDoc()`/`GetDocShell()` across scriptAudit other
HTMLFormElementand form-submission paths (and DOM code generally) that captureGetComposedDoc()orOwnerDoc()into a raw pointer and use it after any step that can dispatch events or run script. - Submission re-entrancyReview the whole submit flow (
DoSubmit, submission constructors,formdata/submitdispatch) for other bare document/docshell pointers held across event dispatch. - Docshell/container lifetimesCheck that
nsDocShell/browsing-context pointers derived from a document stay valid when the document can be torn down mid-operation.
Patch
diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp
index b945dd5f775..618ff72ac9d 100644
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -795,7 +795,7 @@ nsresult HTMLFormElement::SubmitSubmission(
}
// If there is no link handler, then we won't actually be able to submit.
- Document* doc = GetComposedDoc();
+ RefPtr<Document> doc = GetComposedDoc();
RefPtr<nsDocShell> container =
doc ? nsDocShell::Cast(doc->GetDocShell()) : nullptr;
if (!container || IsEditable()) {
Loading diff…
References
On This Page