“Vibe Hacking”: Abusing Developer Trust in Cursor and VS Code Remote Development
In a recent red teaming engagement, we compromised a server that was supposed to be completely isolated. We then discovered a path to breach the internal network, all because a developer was using the server for remote development with Cursor, a popular VS Code fork.
However, this is not a Cursor-specific weakness. The issue lies in the Remote-SSH extension that Cursor inherits directly from VS Code. Therefore, the attack path we discovered likely affects the entire ecosystem of VS Code remote development, putting any developer who connects to an untrusted server at risk.
On the Remote-SSH extension page, Microsoft states:
Only use Remote-SSH to connect to secure remote machines that you trust and that are owned by a party whom you trust. A compromised remote could use the VS Code Remote connection to execute code on your local machine.
Despite clear warnings, a dangerous misconception persists among developers that "remote development" is fully isolated on the server. This belief is increasingly common as developers use remote environments as "sandboxes" to safely run AI agents without risking their local machines.
Given this powerful use case, the assumption of total isolation is understandable. However, Microsoft has suggested that no changes will be made to enhance the extension's safety to meet this expectation. This raises a critical question: how hard is it for your machine to be compromised if you connect to an untrusted server?
The answer: it's easy. Once the server is hacked, you are hacked as well. Thomas Ptacek outlined several attack paths, and our research uncovered a method to compromise the client without delving into low-level details. Our attack works in the default settings of Cursor or VS Code.
When you connect to a remote development server, a malicious extension on the server can execute the workbench.action.terminal.newLocal command to open a terminal on your local machine. This is a terminal on your local machine, not the server. Once the terminal is open, the extension can execute the workbench.action.terminal.sendSequence command to send text to the terminal and get it executed with a new line character (as if pressing Enter). We can also leverage another feature to establish a seamless Command & Control channel between the server and the local machine, but that is beyond the scope of this post.
Our goal in publishing this post is to raise awareness of the risks of remote development and to call for improvements that address the root causes of this issue. Monitoring the ~/.cursor-server directory for changes can serve as a workaround, but it offers limited protection if the server is fully compromised. Securing the Remote-SSH extension is a better approach. For example, requiring user approval when a remote extension attempts to open a new local terminal or send keys to an active local terminal would help block the described attack. As there might be other attack vectors, fixing this issue entirely will take significant effort. A good direction is to move toward secure-by-default designs that don’t rely on users making trust decisions.
Contributors: Tuyen Le, An Nguyen, Khanh Pham