Invoking JavaScript Functions Without Parentheses via Stack Trace Manipulation
A novel technique leveraging Error object internals to execute arbitrary code without standard syntax.
1Exploiting Error Object Internals
The technique involves overwriting the prepareStackTrace function within the JavaScript Error object. This function, typically responsible for formatting stack traces, executes automatically when the stack attribute is accessed. By manipulating this internal mechanism, developers can force the engine to process arbitrary code structures that would otherwise remain dormant during standard execution.
2Function Constructor Signature Alignment
The prepareStackTrace function shares a signature with the standard Function constructor. When triggered, it receives an error object and an array representing code positions. Because the engine expects valid JavaScript code, the challenge lies in transforming these stack trace arrays into executable payloads that bypass standard syntax error checks during runtime.
3Controlling Array Prototype toString
To execute the payload, one must control the output of Array.prototype.toString. By overwriting this method with a constant function returning the desired payload, the stack trace array is forced to represent executable code. This transformation is critical for converting raw stack trace data into a functional string that the engine accepts.
4Leveraging Prototype Pollution Techniques
Prototype pollution provides a secondary method for payload injection. By polluting Object.prototype.message, researchers can manipulate the Error object's toString function directly. This approach allows the payload to remain within the Error realm, effectively sneaking malicious code into existing function structures without needing to modify the global Array prototype directly.
5Generating Arbitrary Function Objects
Combining stack trace manipulation with controlled string conversion enables the generation of arbitrary JavaScript functions. Once the prepareStackTrace logic is aligned with the desired payload, the system treats the generated output as a valid function object. This creates a bridge between internal error handling mechanisms and actual code execution flows.
6The ValueOf Invocation Trick
Final execution is achieved by overriding the default valueOf function of the object. By invoking this object as a primitive, the engine triggers the custom logic. Alternatively, concatenating the object with a string forces a toString call, providing a flexible secondary path to execute the generated function without using traditional parentheses.
7Security Implications for Environments
This method highlights significant risks in environments where prototype pollution is possible. Because the technique relies on modifying core object behaviors, it can bypass standard security filters that look for traditional function invocation patterns. Developers must ensure that prototype access is strictly controlled to prevent such deep-level runtime manipulation of functions.
8Future Research and Mitigation
While this specific payload demonstrates a functional proof-of-concept in browser consoles, the underlying mechanism suggests multiple avenues for further exploitation. Future security audits should focus on how Error objects and prototype chains are handled within complex applications. Monitoring for unexpected modifications to prepareStackTrace remains a vital step in securing JavaScript runtimes.