As of Safari 18, the tabs.executeScript extension API no longer respects the frameId option passed to it, and instead just runs the script in the top frame.
Try running an extension with the following contents on a page with an iFrame (chase.com puts its login form in an iFrame for example).
content.js
console.log("content.js loaded", location.href);
// tabs.executeScript test
browser.runtime.sendMessage({ type: "tabs.executeScript" }).then(() => {
console.log("tabs.executeScript done");
});
// scripting.executeScript test
browser.runtime.sendMessage({ type: "scripting.executeScript" }).then(() => {
console.log("scripting.executeScript done");
});
background.js
browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.type === "tabs.executeScript") {
browser.tabs
.executeScript(sender.tab.id, {
code: 'console.log("THIS IS RUN FROM TABS.EXECUTESCRIPT", location.href);',
frameId: sender.frameId,
})
.then(sendResponse);
} else if (request.type === "scripting.executeScript") {
browser.scripting
.executeScript({
target: { tabId: sender.tab.id, frameIds: [sender.frameId] },
func: () => {
console.log("THIS IS RUN FROM SCRIPTING.EXECUTESCRIPT", location.href);
},
})
.then(sendResponse);
}
});
You'll see that tabs.executeScript runs its contents in the TOP frame, no matter what the target is.
Notably, scripting.executeScript DOES respect the frameId.
Filed with Feedback ID FB15420092