Skip to content

fix(evaluate): reject exposeFunctions in the utility world - #42649

Closed
Ayaan Gazali (ayaangazali) wants to merge 1 commit into
microsoft:mainfrom
ayaangazali:fix-evaluate-world-expose-functions
Closed

Ayaan Gazali (ayaangazali) wants to merge 1 commit into
microsoft:mainfrom
ayaangazali:fix-evaluate-world-expose-functions

Conversation

@ayaangazali

Copy link
Copy Markdown

What is wrong today

exposeFunctions and the new world option cannot be combined, but passing both crashes inside the injected code instead of saying so. On aeebee1d2:

await page.evaluate(async ({ cb }) => await cb(17), { cb: x => x * 2 },
    { exposeFunctions: true, world: 'utility' });
// page.evaluate: TypeError: Cannot read properties of undefined (reading 'callBinding')

Same error from frame.evaluate and locator.evaluate. Reproduced on chromium, firefox and webkit.

Why

PageBinding.createInitScript installs the bindings controller as an init script, and init scripts only run in the main world, so globalThis[kBindingsControllerProperty] is undefined in the utility world. Runtime.addBinding is registered without a world, so the transport is there, but the controller that dispatches through it is not. That is also why the docs sentence saying an exposed function is "technically accessible from all frames and worlds of the page" does not hold:

await page.exposeFunction('f', x => x * 2);
await page.evaluate(() => window.f?.(21) ?? 'NOT PRESENT');                        // 42
await page.evaluate(() => window.f?.(21) ?? 'NOT PRESENT', undefined, { world: 'utility' }); // 'NOT PRESENT'

What this changes

Throws on the combination from assertEvaluateOptions, which every evaluate entry point already calls, and corrects the two doc sentences that promise all worlds. This matches the error JSHandleDispatcher.evaluateExpression already throws for a world it cannot serve.

If bindings are meant to work in the utility world, this guard is the wrong fix and I am happy to close it. The doc sentences would be the part worth keeping either way.

Verified with npm run flint green and tests/page/page-evaluate-world.spec.ts plus the seven adjacent evaluate/expose-function specs (173 tests) passing; the new test fails with the callBinding TypeError when the guard is reverted.

I am a freshman in college trying my best to contribute for the greater good, so please tell me if I have read the intent backwards here.

Bindings are installed by an init script, which only runs in the main
world, so combining exposeFunctions with world: "utility" crashed inside
the injected code with "Cannot read properties of undefined (reading
'callBinding')" instead of reporting the unsupported combination.

Also drop the claim that exposed functions reach all worlds of the page.
Copilot AI lite review requested due to automatic review settings September 10, 2026 01:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@pavelfeldman

Copy link
Copy Markdown
Member

Please file an issue

@ayaangazali

Copy link
Copy Markdown
Author

Done, filed as #42686 with the reproducer and the root cause.

Noted on the issue-first rule, that is on me for opening this cold. I will lead with an issue from now on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants