What it is

Copilot's agents edit files and run commands with your permissions. Whether a hijacked session can skip your approval, reach the network or run a repository's code depends on your VS Code settings, your Copilot CLI settings and what the project ships in .vscode/ and .github/. The audit checks all of it against the Security for Copilot Development guide and tells you exactly what to change.

GitHub Copilot security audit v1.0.0 (read-only, offline)

FAIL  [2] Every agent tool call is auto-approved
              chat.tools.global.autoApprove is true
WARN  [4] The project's .vscode/settings.json changes agent safety settings
              chat.tools.terminal.autoApprove = {"/.*/":true}
WARN  [3] The Copilot CLI sandbox is off (the default)
PASS  [2] Workspace Trust is on
PASS  [2] The agent terminal sandbox is on, with network blocked
PASS  [3] No saved approval matches the audit's risky list
...
Summary: 11 pass, 2 warn, 1 fail, 2 info

Save a report with how-to-fix steps? [h]tml, [t]ext, [c]sv, [j]son, [n]o (default n):

Every finding shows, in brackets, the section of the Copilot guide that explains the fix.

Why you can trust it

Small and knownOfficial Alpine Linux 3.24.2 pinned by digest, plus only bash and jq from Alpine's repositories, pinned to exact versions. A small awk script reads VS Code's JSON with comments.
OpenEverything that runs is the Dockerfile, audit.sh, its mappings file and the shared audit library. You build it yourself from source.
OfflineRuns with --network none: it cannot send anything anywhere.
Read-onlyYour files are mounted read-only and the container's own filesystem is read-only. It changes nothing.
What it can readYour VS Code user settings.json and mcp.json; ~/.copilot/settings.json, permissions-config.json and mcp-config.json; your shell startup files; and the whole project folder you run it from, including any secrets kept in that project. It doesn't mount the Copilot CLI's config.json, session history, logs or the rest of your home folder. Its output names settings, files and commands, and masks values that look like secrets.
UnprivilegedRuns as you, with every Linux capability dropped, and is removed when it exits.

Run it

You need Docker Desktop, Docker Engine or Podman. Nothing else is installed on your machine.

macOS, Linux and WSL2

git clone https://github.com/aisecuritylabs-org/coding-agent-security.git ~/coding-agent-security
cd ~/code/my-app            # the project you want to audit
bash ~/coding-agent-security/copilot/audit/run.sh

Windows: Command Prompt

git clone https://github.com/aisecuritylabs-org/coding-agent-security.git "%USERPROFILE%\coding-agent-security"
cd /d C:\Projects\my-app
powershell -NoProfile -ExecutionPolicy Bypass -File "%USERPROFILE%\coding-agent-security\copilot\audit\run.ps1"

Windows: PowerShell

git clone https://github.com/aisecuritylabs-org/coding-agent-security.git "$HOME\coding-agent-security"
Set-Location C:\Projects\my-app
powershell -NoProfile -ExecutionPolicy Bypass -File "$HOME\coding-agent-security\copilot\audit\run.ps1"

Replace the project folder with the one you want to audit. When code is on your PATH, the launcher also passes your VS Code and Copilot Chat versions to the audit.

What it checks

AreaExamples
Approvals and trustGlobal auto-approve off; new sessions with Default Permissions; no risky terminal commands or sensitive edits auto-approved; Workspace Trust on; no wildcard URL approvals
SandboxesVS Code terminal sandbox on with network off; Copilot CLI sandbox on
Copilot CLINo risky saved approvals; no wildcard allowedUrls; allow-all flags disabled; no --yolo or --allow-all aliases
ExtensionsMCP server inventory in VS Code and the CLI; unpinned servers; servers that read outsider-written content; MCP discovery
RepositoriesA .vscode/settings.json that changes agent settings; project MCP servers; instruction files with fetch instructions or hidden Unicode; cloud agent setup steps; hooks and .github/copilot/settings.json; disguised symlinks; .git/config keys that run programs; .env not ignored
VersionsVS Code 1.132.1 or later and Copilot Chat 1.123.2 or later

The exit code is 0 with no FAIL results and 1 otherwise, so the audit also works in scripts and CI. Copilot cloud agent and organisation policies live on GitHub, which an offline audit can't see; the checklist covers them.

Real attacks it covers

AttackWhat it didCheck
CVE-2025-53773 (Embrace The Red)Injected text made Copilot turn on auto-approve, then run commandsV02, P01
TRA-2025-53 (Tenable)A file-name injection in agent mode, left to Workspace Trust to mitigateV06
Rules File Backdoor (Pillar Security)Hidden Unicode in instruction files steered the agentP06
AgentjackingFake error reports told the agent to run the attacker's commandM02, P03
SymJack (Adversa)Approval prompts showed a harmless link name while the write hit the real targetP10

Reports with how-to-fix steps

After the on-screen summary, the audit asks whether to save a report as HTML,text, CSV or JSON. Every finding explains why it matters, gives the exact fix, maps the risk to OWASP Top 10 for LLM Applications 2025, OWASP Top 10 for Agentic Applications 2026, MITRE ATLAS 2026.09 and NIST AI RMF 1.0, and lists its sources. Reports are saved to copilot-audit-reports in your home folder, never inside the project. Reports mask values that look like secrets, such as tokens, passwords and credentials in URLs, but review a report before you share it.

Fix what it finds

Most findings are fixed by two files: your VS Code user settings and your Copilot CLI settings. Both are below as examples to adapt and test. Every key is from the VS Code AI settings reference and GitHub's Copilot CLI configuration reference.

VS Code user settings

Merge these into your user settings.json (Command Palette: "Preferences: Open User Settings (JSON)"), not into a repository's .vscode/settings.json. On Linux, installbubblewrap and socat before turning the sandbox on; on native Windows the sandbox is experimental and uses chat.agent.sandbox.enabledWindows.

// Baseline VS Code user settings for GitHub Copilot agent mode.
// Merge these into your user settings.json (Command Palette: "Preferences: Open
// User Settings (JSON)"). They belong in user settings, not in a repository's
// .vscode/settings.json, where a cloned project could change them.
// Test these settings before you rely on them; see copilot/README.md.
{
  // Never approve every tool call. VS Code describes this setting as one that
  // "disables critical security protections".
  "chat.tools.global.autoApprove": false,

  // New chat sessions start with Default Permissions. Switch a single session to
  // Bypass Approvals or Autopilot only when a task needs it.
  "chat.permissions.default": "default",

  // Agents stay disabled in folders you have not trusted.
  "security.workspace.trust.enabled": true,

  // Run agent terminal commands in the sandbox (Preview; macOS, Linux and WSL2;
  // on Linux install bubblewrap and socat first). Native Windows uses the
  // experimental "chat.agent.sandbox.enabledWindows" instead.
  "chat.agent.sandbox.enabled": "on",
  // With network off, local sessions on macOS and Linux allow only the domains in
  // chat.agent.allowedNetworkDomains; an empty list blocks all outbound access.
  "chat.agent.sandbox.allowNetwork": false,
  "chat.agent.allowedNetworkDomains": [],

  // Auto-approve only read-only commands. The terminal auto-approve list is a
  // convenience, not a security boundary: anything not listed still asks.
  "chat.tools.terminal.autoApprove": {
    "git status": true,
    "git diff": true,
    "git log": true,
    "ls": true,
    "pwd": true
  },

  // Do not pick up MCP servers configured for other tools.
  "chat.mcp.discovery.enabled": false
}

Copilot CLI settings

Merge these into ~/.copilot/settings.json. With disableBypassPermissionsModeset to "disable", the CLI ignores --yolo and every allow-all flag. To prove it all works in a live session, run the ten-minute self-test.

{
  "sandbox": {
    "enabled": true,
    "allowBypass": false
  },
  "permissions": {
    "disableBypassPermissionsMode": "disable"
  },
  "allowedUrls": [],
  "deniedUrls": []
}

Delete it when you are done

The container is already gone when the audit finishes. To remove the image as well:

docker image rm copilot-audit