Calling JavaScript Functions Without Parentheses: Prototype Pollution & V8 Exploit

This article explains how to invoke JavaScript functions without parentheses by exploiting prototype chain pollution and V8's non-standard Error.prepareStackTrace hook, demonstrating a technique that bypasses security filters and serves as a deep dive into JavaScript's implicit conversions and prototype mechanics.

IT Services Circle
IT Services Circle
IT Services Circle
Calling JavaScript Functions Without Parentheses: Prototype Pollution & V8 Exploit

Prototype Chain Pollution + V8 Execution

The technique leverages JavaScript's prototype chain. All objects eventually point to Object.prototype. By polluting Object.prototype.message and overriding Array.prototype.toString with Error.prototype.toString, then setting Error.prepareStackTrace = Function, a function call can be triggered without parentheses.

Object.prototype.message = 'alert\x281337\x29'; // alert(1337)
Array.prototype.toString = Error.prototype.toString; // override array.toString
Error.prepareStackTrace = Function; // most critical step
const x = new Error;
x.valueOf = x.stack;
+x; // will call alert(1337)

What is Error.prepareStackTrace ?

In the V8 engine, Error.prototype.stack is an accessor property. When accessing an error object's .stack, V8:

Captures the current call stack, generating an array of CallSite objects (structuredStackTrace).

Checks if Error.prepareStackTrace function exists.

If exists, calls it: Error.prepareStackTrace(error, structuredStackTrace), using the return value as .stack.

If not, uses default formatting logic.

Normally, Error.prepareStackTrace customizes stack string formatting, receiving two arguments: error (the error object) and structuredStackTrace (stack frame array).

What Happens When Error.prepareStackTrace = Function ?

When Error.prepareStackTrace is replaced with the Function constructor, accessing x.stack executes: Function(error, structuredStackTrace) The Function constructor treats the last argument as the function body and preceding arguments as parameter names. Thus:

First argument error is stringified as a parameter name.

Second argument structuredStackTrace (the stack frame array) is stringified as the function body.

Because structuredStackTrace is an array, its toString() is called. Since Array.prototype.toString was replaced with Error.prototype.toString, the call becomes Error.prototype.toString.call(structuredStackTrace).

Error Object Stringification

Creating const x = new Error provides the error object. Per spec, Error.prototype.toString reads this.name (default "Error" from Error.prototype.name) and this.message. For x, x.message finds Error.prototype.message (empty string "") and stops, not reaching Object.prototype.message.

structuredStackTrace Array Stringification

When Function stringifies the structuredStackTrace array, it invokes the overridden toString with this as the array:

Read this.name: array has no name, Array.prototype has none, Object.prototype has none → undefined, which Error.prototype.toString replaces with "Error".

Read this.message: array has none, Array.prototype has none, but Object.prototype.message was set to 'alert(1337)' → msg becomes 'alert(1337)'.

Result: "Error: alert(1337)" becomes the function body string.

The function body "Error: alert(1337)" is valid JavaScript: Error: is a label, followed by expression statement alert(1337) . Labels don't affect execution, so the function runs alert(1337) when invoked.

+x Trigger

+x

calls x.valueOf(), which is assigned to x.stack. This triggers the chain: accessing stack invokes Error.prepareStackTrace (now Function), which constructs a function from the stringified arguments and executes it, finally popping alert(1337).

What's the Use?

From a pure engineering standpoint, this code should never appear in production . However, understanding it demonstrates deep knowledge of JavaScript prototype chain traversal and defensive checks.

Security Implications

Bypass WAF & XSS filters: Many WAFs/input filters block requests containing parentheses () to prevent function calls. This technique avoids parentheses entirely.

Bypass ESLint no-new-func rule: The rule forbids new Function(...) to prevent code injection. This exploit uses Function indirectly via Error.prepareStackTrace.

Information leakage & sandbox escape via Error.prepareStackTrace : This hook is a sensitive point. Real CVEs (e.g., CVE-2026-92962 in the vm2 sandbox library) have exploited it.

Educational Value

Seeing "invisible" prototype chain lookups: When writing obj.method(), developers rarely consider how many prototype levels the engine climbs.

Understanding "implicit conversion" as a first-class citizen: +x triggering valueOf is explicit, but Function(error, stackArray) internally calling ToString on both parameters is the core of this attack.

Recognizing power of "non-standard hooks": Error.prepareStackTrace is a V8-specific extension.

Thus, it serves both as an attack technique (bypassing fragile static signature defenses in XSS/WAF bypass and sandbox escape scenarios) and a learning tool (turning abstract concepts of prototype chain dynamism and forced implicit conversion into a runnable, high-impact case study).

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaScriptsecurityXSSV8Prototype ChainPrototype PollutionSandbox EscapeError.prepareStackTrace
IT Services Circle
Written by

IT Services Circle

Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.