Repository navigation
Conversation
…Function The FunctionToString integration's patched toString reads this.__sentry_original__ via getOriginalFunction, which walks the prototype chain for a function that lacks the own property. When the chain loops back through a Proxy the walk never terminates and overflows the stack inside the wrapper, while native toString returns normally. markFunctionWrapped always sets __sentry_original__ as an own non-enumerable property, so reading it as an own property is equivalent for every wrapped function and avoids the unbounded prototype walk. Signed-off-by: Vladimir Babin <vovababin@gmail.com>
bee0f9d to
78f76f3
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 78f76f3. Configure here.
| getClient()?.addIntegration(fts); | ||
|
|
||
| expect(callToString(inspectedFunction)).toBe(expected); | ||
| }); |
There was a problem hiding this comment.
Regression test skips patched toString
Low Severity
The new test binds Function.prototype.toString before addIntegration, so callToString keeps the native function when this case runs first or alone. That path never enters getOriginalFunction and can pass without the overflow fix. Flagged from the review rules: a fix PR's regression test needs to fail without the change.
Triggered by project rule: PR Review Guidelines for Cursor Bot
Reviewed by Cursor Bugbot for commit 78f76f3. Configure here.
logaretm
left a comment
There was a problem hiding this comment.
Thanks for digging into this! Per our contributing guide, we would have appreciated a discussion first before taking it on, since we shipped two PRs in this area.
I'm closing this because Object.prototype.hasOwnProperty.call looks up .call every time it runs, so a page that hooks Function.prototype.call sends the wrapper into infinite recursion again, which is the same kind of re-entry #25921 fixed.
Here is an example:
// e.g. an anti-tamper or call-tracing script
Function.prototype.call = function (thisArg, ...args) {
const isNative = this.toString().includes('[native code]');
return Reflect.apply(this, thisArg, args);
};
setTimeout.toString(); // RangeError: Maximum call stack size exceeded

Fixes #25963
What
functionToStringIntegrationpatchesFunction.prototype.toStringto return the original source for wrapped functions. The wrapper callsgetOriginalFunction(this), which readsthis.__sentry_original__. For a function that does not have that own property, the read walks the prototype chain. If the chain loops back through aProxy, the walk never terminates and overflows the stack inside the wrapper frame, while nativetoStringreturns normally for the same function. Anti-tamper/fingerprinting probes (e.g. Castle bot detection) use exactly this kind of cyclic-proxy probe to detect patched natives.This remained after #25921 / #25922, which fixed the
applyre-entry and huge-argument-list overflows — not this property lookup.Fix
markFunctionWrappedalways sets__sentry_original__as an own non-enumerable property, so reading it as an own property is equivalent for every legitimately wrapped function and avoids the unbounded prototype-chain walk:Tests
Added a regression test to the existing
FunctionToStringsuite that gives a function a prototype chain looping through aProxyand asserts the patchedtoString(invoked via the boundFunction.prototype.callform, as the reported probe does) returns the native result instead of overflowing.Validation (local):
does not overflow the stack when the prototype chain loops through a Proxyfails withRangeError: Maximum call stack size exceededatgetOriginalFunction(src/utils/object.ts).Test Files 2 passed (2),Tests 46 passed (46)— the new test plus all existingfunctiontostringandobjecttests pass.