"The fact that this vulnerability has the maximum CVSS score of 10 and is extremely popular means its potential impact is widespread and critical," Oxeye architect Yuval Ostrovsky and security researcher Gal Goldshtein wrote in a blog post published Oct. 10.
Oxeye found the flaw on Aug. 16 and informed the project owners two days later. On Aug. 28, GitHub issued CVE-2022-36067 and gave the vulnerability the highest risk rating possible.
The project's maintainers reacted swiftly to issue a patch for Sandbreak in vm2 version 3.9.11, which should be applied by anyone using the sandbox because of the heightened risk of vulnerability, the researchers said.
Sandboxes: Historically Trustworthy
Like all sandboxes, vm2 offers an isolated environment where applications can run trusted code, serving a vital purposes in modern applications because developers or network administrators can use them to run programs or open files without affecting the app, system, or platform in which they run.
Software developers often use sandboxes to test new programming code, and they are well known as an important tool in cybersecurity research, allowing researchers to test potentially malicious software without harming other parts of a network or app environment.
Indeed, the fact that a sandbox is so universally trusted is what makes the Sandbreak flaw so critical and should sound an alarm across all sandbox users to shore up their implementations, the researchers said.
"By their very definition, sandboxes are considered safe places and trusted as mechanisms that isolate potentially dangerous code from our applications," they wrote in the post. "But what would happen if this trust was compromised?"
Researchers explored just that in their investigation of Sandbreak, which they discovered while analyzing previous security lapses disclosed to the team maintaining vm2.
The bug exists in the vm2 bug reporter, which would allow cyberattackers to abuse the error mechanism in Node.js. They could customize the call stack of an error that occurred in the app to escape the sandbox, the researchers disclosed.
"Customizing the call stack can achieve this by implementing the 'prepareStacktrace' method under the global 'Error' object,'" the researchers explained in the post. "This means that when an error occurs and the 'stack' property of the thrown error object is accessed, Node.js will call this method while providing it with a string representation of the error alongside an array of 'CallSite' objects as arguments."
One of the methods exposed by the CallSite objects because of the issue is "getThis," which is responsible for returning the “this” object that was available in the related stack frame, the researchers found.
This behavior can lead to sandbox escapes because some of the "CallSite" objects "may return objects created outside the sandbox when invoking the 'getThis' method," they wrote. If an attackers could gain hold of a "CallSite" object created outside of the sandbox, they could access Node's global objects and execute arbitrary system commands from there.
Bypassing the Mitigation
The maintainers of vm2 were aware that overriding "prepareStackTrace" could indeed lead to a sandbox escape. They tried to mitigate the escape path by wrapping the Error object and the "prepareStackTrace" method with their own implementation, which succeeded in preventing anyone from overriding the method and performing the escape, they said.
Knowing that the prepareStackTrace function of the Error object is the function they needed to override to escape the sandbox, Oxeye researchers went even further and decided to try to override the global Error object with their own object.
Doing this implemented the prepareStackTrace function, which allowed them to escape the sandbox. A few simple steps later and they had access to the currently executing process and could execute commands on the system running the sandbox, they said.
Using Sandboxes Safely
Although sandboxes by their very nature are meant to safely run untrusted code within an app or system, enterprises shouldn't automatically assume they are without risk, the researchers warned.
However, if using a sandbox in an environment is unavoidable, Oxeye recommends reducing risk by separating the logical, sensitive part of an application from the microservice that runs the sandbox code.
This will ensure that "if a threat actor successfully breaks out from the sandbox, the attack surface is limited to the isolated microservice," the researchers wrote.
"The dynamic nature of the language widens the attack surface for a potential attacker, making defending against such attacks much harder," researchers observed in their post.