Unauthenticated Remote Code Execution in Spotify’s Backstage

We discussed this vulnerability during Episode 171 on 28 November 2022

This blogpost is essentially using a previous sandbox escape they discovered against Backstage, which is Spotify’s incubated solution for managing infrastructure and microservices and such. Backstage includes software templates, which can contain ` message` parameter that gets rendered in Nunjucks (a JS templating engine). The environment is sandboxed via the vm2 JS sandbox library.

The idea behind the sandbox escape is the fact that you can access global Node objects outside the sandbox by overriding the prepareStackTrace() method of the Error object. The intent is to allow you to customize the callstack, and so the prepareStackTrace() method will be invoked with an array of CallSite objects that represent stack frames. Some of those stack frames may have objects that are outside the sandbox. Knowing this, the vm2 maintainers tried to prevent this strategy by wrapping the Error object with their own implementation that would prevent overriding prepareStackTrace(). The problem is, an attacker can then just override the Error object again to implement it.

In the case of Backstage, there were some challenges due to their use of strict mode functions. Functions that are in strict mode cannot access their receivers. They iterated the call stack and found the earliest strict mode function was renderString2(). What this does isn’t really important, what is important is that this method can be overridden to force it to run in non-strict mode. They discovered renderString2() was also called when any error was thrown. By overriding it and intentionally triggering an error, they can then resume the Error object override attack to escape the sandbox and achieve RCE.