Skip to content

Reject cyclic prototypes on scriptlet proxies - #67

Open
qiu-x wants to merge 3 commits into
mainfrom
proxy-cycle-fix
Open

qiu-x wants to merge 3 commits into
mainfrom
proxy-cycle-fix

Conversation

@qiu-x

@qiu-x qiu-x commented Nov 9, 2026 •

Copy link
Copy Markdown

This fix resolves an issue with scriptlet injection that appeared on multiple websites using an older version of Akamai Bot Manager (probably 2.x).

Websites with the issue include:

Click me

I verified that uBO also has this issue on the listed sites (but doesn't include any rules to trigger the problem unlike us).
It might be worth it to also try fixing this upstream.

Context:
Akamai’s prototype probe can create a cycle on the proxied Function.prototype.toString, causing fn.toString() calls across the page to overflow the stack.

run() now wraps Proxy with a setPrototypeOf trap that checks the proposed chain before changing it. The check rejects chains reaching the proxy or its target, including through other scriptlet proxies. Tortoise-and-hare traversal terminates walks over already-cyclic chains.

Handlers have a null prototype and contain only scriptlet-owned traps, preventing page changes to Object.prototype from injecting traps. Traversal can still invoke traps on page-owned proxies, unlike native cycle checks; this remains an accepted detection and nontermination risk.

Note: kroger.com and fredmeyer.com are already fixed by a site specific rule that was added here.

Akamai's prototype probe can create a cycle on the proxied
Function.prototype.toString, causing fn.toString() calls across
the page to overflow the stack.

run() now wraps Proxy with a setPrototypeOf trap that checks the
chain before changing it. The check rejects chains reaching the
proxy or its target and stops at other proxies from the same wrapper.

Returning false makes Reflect.setPrototypeOf() return false and
Object.setPrototypeOf() throw a TypeError.
Copy scriptlet-owned traps into a null-prototype handler so page changes
to Object.prototype cannot inject traps or interfere with cycle checks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants