CVE-2026-28942
Overview
Background
- Invoker commands
- HTML button command/commandfor lets a button drive a dialog (close/requestClose); the button’s value is passed as the dialog returnValue.
- beforetoggle event
- An author-observable event fired as a dialog opens/closes; its handler can run arbitrary script and mutate the DOM mid-operation.
- Attribute-backed string lifetime
- A string taken from an element’s attribute can be invalidated if the attribute is changed while the string is still in use.
Root Cause Analysis
This fixes a use-after-free (observed as a crash / ASan hit) in HTMLDialogElement command handling by snapshotting the invoker’s value string before dispatching author-observable events. HTMLDialogElement::handleCommandInternal, for the Close and RequestClose commands, called close(invoker.value().string(), &invoker) / requestClose(invoker.value().string(), &invoker) — passing a string derived from the invoker button’s value attribute directly as an argument while also passing &invoker. close()/requestClose() dispatch events (e.g. beforetoggle/close) that run author script; that script can mutate or remove the invoker button’s value attribute during the call. Because the string was obtained from the invoker’s attribute storage as part of the call, author code mutating that attribute mid-close can invalidate the underlying string data the operation is still using, yielding a use-after-free of the attribute-backed string.
The fix hoists the value into an owned local first (String value = invoker.value().string();) and passes that local to close(value, &invoker) / requestClose(value, &invoker), so the value is captured before any event fires and cannot be invalidated by author script that alters the invoker during the close sequence.
The restored invariant is that the command value is a stable snapshot taken before author-observable side effects run. The regression test opens a dialog, and in a beforetoggle handler removes the button’s value attribute while the close command runs, expecting no crash and PASS returnValue.
Attack Path
- Set up a dialog + invoker Create an open <dialog> with a <button command=close commandfor=dialog> and a value attribute.
- Hook the close event Add a beforetoggle listener that removes/mutates the button’s value attribute.
- Invoke close Click the button so handleCommandInternal reads invoker.value().string() and calls close(), firing beforetoggle.
- Free during use The handler mutates the invoker’s value attribute mid-close, invalidating the in-use string — a use-after-free in WebContent.
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
HTMLDialogElement::handleCommandInternalSource/WebCore/html/HTMLDialogElement.cpp |
modified | Copies invoker.value().string() into a local String before calling close()/requestClose(), so author script that mutates the invoker during the close cannot invalidate the value in use. |
Files Changed
LayoutTests/fast/html/dialog-close-from-button-crash-expected.txtLayoutTests/fast/html/dialog-close-from-button-crash.htmlSource/WebCore/html/HTMLDialogElement.cpp
Audit Directions
- Same file: other command handlersAudit HTMLDialogElement and other command/invoker handlers for element-derived strings passed into calls that dispatch events; snapshot before dispatch.
- Mutate-during-event patternGrep for value()/getAttribute() results passed directly into methods that fire events (dispatchEvent, toggle, focus) where author script can invalidate them.