Copilot Hooks
Akto Guardrails for GitHub Copilot provides security validation for AI-assisted development across VS Code and the CLI. It intercepts prompts when submitted and tool executions before and after they run, validates against security policies, blocks risky behavior, and reports events to your Akto dashboard.
Key Features
✅ Zero Installation - No standalone apps to install
✅ Transparent Integration - Uses GitHub Copilot's native hook mechanism in both VS Code and CLI
✅ Real-time Tool Blocking - Can block dangerous tool executions before they run
✅ Centralized Monitoring - All events reported to Akto dashboard
✅ Agent Registration - Automatically registers the device (ID + username) with Akto on first hook invocation
✅ Flexible Deployment - Supports Argus and Atlas modes
✅ Configurable Behavior - Blocking or observation modes
✅ Cross-platform - Full support for macOS, Linux, and Windows (including Azure Virtual Desktop)
⚠️ Prompt Monitoring Only - GitHub Copilot limitation prevents blocking prompts at submission
How Hooks Works
GitHub Copilot's hook system executes custom scripts at three critical points in both VS Code and the CLI:
3 Hook Points:
userPromptSubmitted- Monitors prompts when submitted to Copilot (reporting only, cannot block)preToolUse- Validates tool use before execution and can block dangerous operationspostToolUse- Ingests tool execution results for monitoring and audit
GitHub Copilot Limitation: The userPromptSubmitted hook cannot block prompt execution. Prompts flagged by guardrails will still reach the LLM. Only preToolUse can prevent operations from executing. For complete prompt blocking, consider using a network proxy.
File Structure
Key Files:
Wrapper scripts (
.sh/.ps1): Set environment variables, invoke Python scripts⚠️ Contains
AKTO_DATA_INGESTION_URLplaceholder - Must be set to your Akto instance URL⚠️ Contains
AKTO_API_TOKENplaceholder - Must be set for agent registration.shused on macOS/Linux;.ps1used on Windows
Python scripts (
.py): Core validation logic and Akto API communicationakto_machine_id.py: Generates unique device identifiers — uses Windows registry (MachineGuid) on Windows, IOPlatformUUID on macOS,/etc/machine-idon Linuxakto_heartbeat.py: Sends agent registration (device ID, username, OS) to Akto on each hook invocation, rate-limited to once per 30 seconds via a local timestamp cachehooks.json: Links hooks to wrapper scripts — usesbashkey on macOS/Linux andpowershellkey on Windows
Note:
hooks.jsonis loaded from the project root's.github/hooks/directory.
Setup Guide
Prerequisites
GitHub Copilot CLI installed and authenticated — run
copilot(macOS/Linux) orcopilot.exe(Windows) to verifyVS Code with the GitHub Copilot extension (for VS Code hook support)
Akto instance URL
Python 3
macOS / Linux: bash or zsh
Windows: PowerShell 5.1+ (built-in on Windows 10/11, including Azure Virtual Desktop pooled sessions)
Project-level Installation
Install hooks inside a specific repository at <project-root>/.github/hooks/. Copilot CLI auto-loads hooks.json from this location when you run copilot from the project root. These hooks only fire for Copilot CLI sessions launched from this repository.
Use this approach when hooks should only apply inside one repository — e.g. committed alongside the codebase as a per-project security control. For machine-wide coverage that applies to every Copilot CLI session regardless of directory, see Global (User-level) Installation below.
Create the Hooks Directory
macOS / Linux:
Windows (PowerShell):
Download Hook Scripts
macOS / Linux:
Windows (PowerShell):
Configure URLs and API Token ⚠️ CRITICAL STEP
All wrapper scripts contain two placeholders that must be replaced before hooks will work:
{{AKTO_DATA_INGESTION_URL}}— your Akto instance URL (required for event ingestion){{AKTO_API_TOKEN}}— your Akto API token (required for agent registration auth; obtain from Akto Atlas → Connectors → Setup Guardrail card)
DATABASE_ABSTRACTOR_SERVICE_URL is built into the hooks and defaults to https://cyborg.akto.io automatically — no action needed for SaaS users.
macOS / Linux — automated replacement:
Windows (PowerShell) — automated replacement:
Manual replacement (alternative):
Edit each wrapper script and replace the two placeholders with your actual values.
Files to update on macOS/Linux:
akto-validate-prompt-wrapper.shakto-validate-pre-tool-wrapper.shakto-validate-post-tool-wrapper.sh
Files to update on Windows:
akto-validate-prompt-wrapper.ps1akto-validate-pre-tool-wrapper.ps1akto-validate-post-tool-wrapper.ps1
Verify hooks.json Configuration
The hooks.json file should already be configured after downloading. Verify it contains all three hooks:
Windows note: The
powershellkey is used automatically on Windows. The.ps1wrapper sets all required environment variables before invoking the Python script — equivalent to what the.shwrappers do on macOS/Linux.
Note:
timeoutSecis in seconds (30 = 30 seconds). Hooks are loaded from.github/hooks/hooks.jsonin the directory you run copilot from.
Configure Hook Behavior (Optional)
Edit wrapper scripts to customize:
macOS / Linux — in each *-wrapper.sh:
Windows — in each *-wrapper.ps1:
Mode Options:
Argus: Standard validation and reporting
Atlas: Includes device-specific metadata
Sync Mode:
true: Validates in real-time;
preToolUseblocks dangerous tool executionsfalse: Monitoring only; all tool executions pass through but are logged
Verify Installation
macOS / Linux:
Windows (PowerShell):
Check logs to confirm hooks are working:
macOS / Linux:
Windows (PowerShell):
Global (User-level) Installation
The project-level install above applies only inside the repo it lives in. To apply Akto Guardrails to every Copilot CLI session on your machine — regardless of which directory you launch from — install hooks once at the user level. Wrappers live at ~/.github/hooks/ and are registered directly in ~/.copilot/config.json (no per-repo hooks.json).
Use the project-level install when hooks should only apply inside one repository (e.g. committed as a per-project security control). Use the user-level install below when every Copilot CLI invocation on your machine should go through Akto Guardrails.
Create the Global Hooks Directory
macOS / Linux:
Windows (PowerShell):
Download Hook Scripts
Download the eight hook files into the directory you just created. Do not download hooks.json — user-level hooks are defined directly in ~/.copilot/config.json (step 4 below), not in a separate hooks.json file.
Files you will download (all from https://raw.githubusercontent.com/akto-api-security/akto/master/apps/mcp-endpoint-shield/github-cli-hooks/):
1
akto-validate-prompt-wrapper.sh
akto-validate-prompt-wrapper.ps1
2
akto-validate-prompt.py
akto-validate-prompt.py
3
akto-validate-pre-tool-wrapper.sh
akto-validate-pre-tool-wrapper.ps1
4
akto-validate-pre-tool.py
akto-validate-pre-tool.py
5
akto-validate-post-tool-wrapper.sh
akto-validate-post-tool-wrapper.ps1
6
akto-validate-post-tool.py
akto-validate-post-tool.py
7
akto_machine_id.py
akto_machine_id.py
8
akto_heartbeat.py
akto_heartbeat.py
macOS / Linux — copy the entire block below, paste it into your terminal, press Enter:
Confirm all 8 files landed in the directory:
Windows (PowerShell) — copy the entire block below, paste it into PowerShell, press Enter:
Confirm all 8 files landed in the directory:
Configure Wrappers ⚠️ CRITICAL STEP
Each of the three wrapper scripts you downloaded has four things that need to be set before Copilot CLI can run them. The block below handles all four in one shot.
What the block does:
Replaces
{{AKTO_DATA_INGESTION_URL}}inside the wrappers with your Akto instance URL.Replaces
{{AKTO_API_TOKEN}}inside the wrappers with your Akto API token.Changes the relative
./.github/hooks/akto-validate-*.pyreference inside each wrapper to an absolute path (e.g./Users/you/.github/hooks/akto-validate-*.py). User-level wrappers are invoked from whatever directory the user launched Copilot CLI from, so relative paths would not resolve.Adds
export AKTO_CONNECTOR="github_copilot_cli"(or$env:AKTO_CONNECTORon Windows). Without this the connector defaults tovscodeand CLI traffic is mis-attributed in the Akto dashboard.
macOS / Linux — first, edit the two values at the top of the block (AKTO_URL and AKTO_API_TOKEN) with your real Akto instance URL and API token. Then copy the entire block, paste it into your terminal, and press Enter:
Confirm no placeholders are left and the wrappers look correct:
Windows (PowerShell) — first, edit the two values at the top of the block ($AKTO_URL and $AKTO_API_TOKEN) with your real Akto instance URL and API token. Then copy the entire block, paste it into PowerShell, and press Enter:
Confirm no placeholders are left:
Register Hooks in ~/.copilot/config.json
User-level hooks are declared directly in the Copilot CLI user config at ~/.copilot/config.json. There is no separate hooks.json file at the user level, and the hooks object here has no outer version wrapper (that version wrapper is only for repository-level .github/hooks/*.json).
The block below backs up your existing config.json to config.json.bak, then merges in the three Akto hooks (preserving any other keys you already have such as trusted_folders, loggedInUsers, banner, etc).
Requires jq on macOS/Linux (usually preinstalled; if not: brew install jq on macOS, sudo apt install jq on Ubuntu/Debian). Windows uses PowerShell's built-in ConvertFrom-Json / ConvertTo-Json — no extra install.
macOS / Linux — copy the entire block below, paste it into your terminal, press Enter:
Verify the hooks section was written correctly:
Windows (PowerShell) — copy the entire block below, paste it into PowerShell, press Enter:
Verify the hooks section was written correctly:
Reference — what the resulting hooks section in ~/.copilot/config.json should look like (macOS/Linux example):
Verify Installation
Three checks in order: validate the config file, run one hook manually end-to-end, then launch Copilot CLI from a directory that is not an Akto-hooked repo so you can confirm hooks fire globally.
Check 1 — Validate the hooks block in ~/.copilot/config.json.
macOS / Linux:
Windows (PowerShell):
Expected: the three events (userPromptSubmitted, preToolUse, postToolUse) each pointing at your absolute wrapper paths.
Check 2 — Run the pre-tool hook manually with a deliberately-flagged payload. The hook should exit 0 and print a JSON permissionDecision: "deny" object to stdout.
macOS / Linux:
Expected output (roughly):
Windows (PowerShell):
Check 3 — Launch Copilot CLI from any directory (e.g. /tmp on macOS/Linux, $env:TEMP on Windows) to prove hooks fire regardless of project. Submit a test prompt that includes an email address, or ask Copilot to run a shell command that would print one, and watch the logs fill up in real time.
Open a second terminal and tail the logs:
macOS / Linux:
Windows (PowerShell):
Then in your first terminal:
macOS / Linux:
Windows (PowerShell):
You should see Connector: github_copilot_cli and guardrail verdicts appearing in the log files for every prompt and tool call — confirming hooks are active globally and not scoped to a project.
Paths in the bash / powershell fields of ~/.copilot/config.json must be absolute. Copilot CLI runs these commands from whatever directory the user launched from, so relative paths (e.g. ./.github/hooks/...) will silently fail to resolve.
Configuration Reference
Wrapper Script Variables
AKTO_DATA_INGESTION_URL
✅ Yes
—
Your Akto instance URL for event ingestion
AKTO_API_TOKEN
✅ Yes
—
Akto API token used to authenticate heartbeat
MODE
No
argus
argus or atlas
AKTO_SYNC_MODE
No
true
true = blocking, false = observe only
AKTO_TIMEOUT
No
5
Request timeout in seconds
DEVICE_ID
No
auto-detected
Override the machine ID
LOG_DIR
No
~/akto/.github/akto/copilot/logs
Log directory
LOG_LEVEL
No
INFO
Log level (DEBUG, INFO, WARNING, ERROR)
DATABASE_ABSTRACTOR_SERVICE_URL
No
https://cyborg.akto.io
Override cyborg URL — self-hosted deployments only
Environment Variables (Optional)
Override defaults via environment variables (e.g. in ~/.bashrc or ~/.zshrc):
Agent Registration
Each hook automatically registers the device with Akto on first invocation (and refreshes every 30 seconds). This mirrors the heartbeat mechanism used by the mcp-endpoint-shield Go agent.
What is registered:
moduleType
GITHUB_COPILOT_CLI_HOOKS
name
Machine ID (hardware-based, persistent)
additionalData.username
System username
additionalData.os
Operating system (Windows, Darwin, Linux)
additionalData.connector
github_copilot_cli or vscode
How machine ID is resolved by platform:
Windows
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid (registry)
macOS
IOPlatformUUID via ioreg
Linux
/etc/machine-id
Fallback
MAC address via uuid.getnode()
Rate limiting: Registration is sent at most once every 30 seconds. The timestamp is cached in <log_dir>/last_heartbeat. The persistent agent ID is stored in <log_dir>/agent_id — this ID survives across hook invocations so the device appears as a single registered agent in the Akto dashboard.
Troubleshooting
Hooks Not Executing
Ingestion URL Not Configured
macOS / Linux:
Windows (PowerShell):
Windows: Hooks Not Running
Step 1 — Verify .ps1 wrapper files were downloaded:
If missing, re-run the Windows download step above.
Step 2 — Unblock downloaded files:
Files downloaded via Invoke-WebRequest are marked as "from the internet" by Windows. Under RemoteSigned execution policy (default on Windows 10/11), these are blocked. Run:
Step 3 — Check execution policy:
The hooks.json already includes -ExecutionPolicy Bypass in the powershell command, which overrides the policy per-invocation regardless of system settings.
Check Logs for Errors
Events Not in Dashboard
Hook Timing Out
Increase timeoutSec in hooks.json (value in seconds, e.g. "timeoutSec": 60). Ensure AKTO_DATA_INGESTION_URL is reachable from your machine.
Permission Denied on Scripts
Uninstallation
Complete Removal
Selective Removal (Keep Logs)
Backup Before Removal
Verify Removal
Enterprise Deployment
Automated Deployment Script
macOS / Linux:
Windows (PowerShell) — works on Azure Virtual Desktop pooled sessions:
Deploy to developers (Windows):
Quick Setup Summary
Resources
GitHub Copilot CLI: https://github.com/features/copilot/cli
Support: support@akto.io
Community: https://www.akto.io/community
Last updated