Skip to content
GitHub Agentic Workflows

Security Architecture

GitHub Agentic Workflows implements a defense-in-depth security architecture that protects against prompt injection, rogue MCP servers, and malicious agents. This document provides visual diagrams of the key security mechanisms.

The security architecture operates across multiple layers: compilation-time validation, runtime isolation, permission separation, network controls, and output sanitization.

flowchart TB
    subgraph Input["📥 Input Layer"]
        WF[/"Workflow (.md)"/]
        IMPORTS[/"Imports & Includes"/]
        EVENT[/"GitHub Event
(Issue, PR, Comment)"/] end subgraph Compile["🔒 Compilation-Time Security"] SCHEMA["Schema Validation"] EXPR["Expression Safety Check"] PIN["Action SHA Pinning"] SCAN["Security Scanners
(actionlint, zizmor, poutine)"] end subgraph Runtime["⚙️ Runtime Security"] PRE["Pre-Activation
Role & Permission Checks"] ACT["Activation
Content Sanitization"] AGENT["Agent Execution
Read-Only Permissions"] REDACT_MAIN["Secret Redaction
Credential Protection"] end subgraph Isolation["🛡️ Isolation Layer"] AWF["Agent Workflow Firewall
Network Egress Control"] MCP["MCP Server Sandboxing
Container Isolation"] TOOL["Tool Allowlisting
Explicit Permissions"] end subgraph Output["📤 Output Security"] DETECT["Threat Detection
AI-Powered Analysis"] SAFE["Safe Outputs
Permission Separation"] SANITIZE["Output Sanitization
Content Validation"] end subgraph Result["✅ Controlled Actions"] ISSUE["Create Issue"] PR["Create PR"] COMMENT["Add Comment"] end WF --> SCHEMA IMPORTS --> SCHEMA SCHEMA --> EXPR EXPR --> PIN PIN --> SCAN SCAN -->|".lock.yml"| PRE EVENT --> ACT PRE --> ACT ACT --> AGENT AGENT <--> AWF AGENT <--> MCP AGENT <--> TOOL AGENT --> REDACT_MAIN REDACT_MAIN --> DETECT DETECT --> SAFE SAFE --> SANITIZE SANITIZE --> ISSUE SANITIZE --> PR SANITIZE --> COMMENT

The safe outputs system ensures AI agents never have direct write access to your repository. The agentic portion runs with minimal read-only permissions, while separate jobs handle validated GitHub API operations.

flowchart LR
    subgraph AgentJob["Agent Job
🔐 Read-Only Permissions"] AGENT["AI Agent Execution"] OUTPUT[/"agent_output.json
(Artifact)"/] AGENT --> OUTPUT end subgraph Detection["Threat Detection Job"] ANALYZE["Analyze for:
• Prompt Injection
• Secret Leaks
• Malicious Patches"] end subgraph SafeJobs["Safe Output Jobs
🔓 Write Permissions (Scoped)"] direction TB ISSUE["create_issue
issues: write"] COMMENT["add_comment
issues: write"] PR["create_pull_request
contents: write
pull-requests: write"] LABEL["add_labels
issues: write"] end subgraph GitHub["GitHub API"] API["GitHub REST/GraphQL API"] end OUTPUT -->|"Download Artifact"| ANALYZE ANALYZE -->|"✅ Approved"| SafeJobs ANALYZE -->|"❌ Blocked"| BLOCKED["Workflow Fails"] ISSUE --> API COMMENT --> API PR --> API LABEL --> API

The AWF provides network egress control for the Copilot engine, preventing unauthorized data exfiltration and limiting access to only explicitly allowed domains.

flowchart TB
    subgraph Agent["AI Agent Process"]
        COPILOT["Copilot CLI"]
        WEB["WebFetch Tool"]
        SEARCH["WebSearch Tool"]
    end

    subgraph Firewall["Agent Workflow Firewall (AWF)"]
        WRAP["Process Wrapper"]
        ALLOW["Domain Allowlist"]
        LOG["Activity Logging"]

        WRAP --> ALLOW
        ALLOW --> LOG
    end

    subgraph Network["Network Layer"]
        direction TB
        ALLOWED_OUT["✅ Allowed Domains"]
        BLOCKED_OUT["❌ Blocked Domains"]
    end

    subgraph Ecosystems["Ecosystem Bundles"]
        direction TB
        DEFAULTS["defaults
certificates, JSON schema"] PYTHON["python
PyPI, Conda"] NODE["node
npm, npmjs.com"] CUSTOM["Custom Domains
api.example.com"] end COPILOT --> WRAP WEB --> WRAP SEARCH --> WRAP ALLOW --> ALLOWED_OUT ALLOW --> BLOCKED_OUT DEFAULTS --> ALLOW PYTHON --> ALLOW NODE --> ALLOW CUSTOM --> ALLOW ALLOWED_OUT --> INTERNET["🌐 Internet"] BLOCKED_OUT --> DROP["🚫 Dropped"]

Configuration Example:

engine: copilot
network:
firewall: true
allowed:
- defaults # Basic infrastructure
- python # PyPI ecosystem
- node # npm ecosystem
- "api.example.com" # Custom domain

Model Context Protocol (MCP) servers run in isolated containers with explicit tool filtering, preventing unauthorized access and limiting the attack surface.

flowchart TB
    subgraph Agent["AI Agent"]
        ENGINE["AI Engine
(Copilot, Claude, Codex)"] end subgraph MCPLayer["MCP Server Layer"] direction TB subgraph GitHub["GitHub MCP"] GH_TOOLS["Enabled Tools:
• issue_read
• list_commits
• search_code"] GH_BLOCKED["Blocked Tools:
• delete_repository
• update_branch_protection"] end subgraph Custom["Custom MCP (Docker)"] CONTAINER["🐳 Isolated Container"] NET["Network Allowlist"] ENV["Env Var Injection"] end subgraph HTTP["HTTP MCP"] ENDPOINT["HTTPS Endpoint"] HEADERS["Secure Headers"] end end subgraph Toolfilter["Tool Filtering"] ALLOWED["allowed: [tool1, tool2]"] DENIED["❌ Unlisted tools blocked"] end ENGINE <-->|"stdio/HTTP"| GitHub ENGINE <-->|"stdio"| CONTAINER ENGINE <-->|"HTTP"| ENDPOINT ALLOWED --> GH_TOOLS ALLOWED --> GH_BLOCKED CONTAINER --> NET CONTAINER --> ENV ENDPOINT --> HEADERS

Security Features:

  • Container Isolation: Custom MCP servers run in Docker containers with no shared state
  • Network Controls: Per-container domain allowlists via Squid proxy
  • Tool Allowlisting: Explicit allowed: lists restrict available operations
  • Secret Injection: Secrets passed via environment variables, never in config files

The threat detection system analyzes agent output before any GitHub API operations are performed, blocking malicious content, secret leaks, and prompt injection attempts.

flowchart TB
    subgraph Input["Agent Output"]
        JSON[/"agent_output.json"/]
        PATCH[/"aw.patch
(Git Diff)"/] PROMPT[/"prompt.txt
(Workflow Context)"/] end subgraph Analysis["Threat Analysis"] direction TB AI["AI-Powered Detection"] CUSTOM["Custom Security Steps"] subgraph Checks["Detection Checks"] INJECT["Prompt Injection
Hidden instructions
Jailbreak attempts"] SECRETS["Secret Leaks
API keys, tokens
Credentials"] MALICIOUS["Malicious Patches
Backdoors
Vulnerabilities"] end end subgraph Decision["Decision"] SAFE_CHECK{{"Threats
Detected?"}} end subgraph Outcome["Outcome"] PROCEED["✅ Proceed to Safe Outputs"] BLOCK["❌ Block & Fail Workflow"] end JSON --> AI PATCH --> AI PROMPT --> AI AI --> Checks Checks --> CUSTOM CUSTOM --> SAFE_CHECK SAFE_CHECK -->|"No"| PROCEED SAFE_CHECK -->|"Yes"| BLOCK

Defense-in-Depth Options:

  • AI Detection: Default AI-powered analysis using the workflow engine
  • Custom Steps: Integration with security scanners (Semgrep, TruffleHog, LlamaGuard)
  • Custom Prompts: Domain-specific detection instructions

Security validation happens at compile time, before workflows ever run, catching misconfigurations and enforcing best practices.

flowchart TB
    subgraph Source["Source Files"]
        MD[/"workflow.md"/]
        IMPORTS[/"imports/*.md"/]
    end

    subgraph Validation["Schema & Expression Validation"]
        SCHEMA["JSON Schema Validation
• Valid frontmatter fields
• Correct types & formats"] EXPR["Expression Safety
• Allowlisted expressions only
• No secrets in expressions"] end subgraph Pinning["Action Pinning"] SHA["SHA Resolution
actions/checkout@sha # v4"] CACHE[/"actions-lock.json
(Cached SHAs)"/] end subgraph Scanners["Security Scanners"] ACTIONLINT["actionlint
Workflow linting
Shell script checks"] ZIZMOR["zizmor
Security vulnerabilities
Privilege escalation"] POUTINE["poutine
Supply chain risks
Third-party actions"] end subgraph Strict["Strict Mode Enforcement"] PERMS["❌ No write permissions"] NETWORK["✅ Explicit network config"] WILDCARD["❌ No wildcard domains"] DEPRECATED["❌ No deprecated fields"] end subgraph Output["Compilation Output"] LOCK[/".lock.yml
(Validated Workflow)"/] ERROR["❌ Compilation Error"] end MD --> SCHEMA IMPORTS --> SCHEMA SCHEMA --> EXPR EXPR --> SHA SHA <--> CACHE SHA --> ACTIONLINT ACTIONLINT --> ZIZMOR ZIZMOR --> POUTINE POUTINE --> Strict Strict -->|"All Checks Pass"| LOCK Strict -->|"Violation Found"| ERROR

Compilation Commands:

# Standard compilation
gh aw compile
# Strict mode enforces security constraints (no write permissions, explicit network config)
gh aw compile --strict
# Add security scanners for additional validation (optional, not included by default)
gh aw compile --strict --actionlint --zizmor --poutine

All user-generated content is sanitized before being processed by AI agents, preventing prompt injection and other attacks. The sanitization pipeline applies multiple transformations to neutralize potentially malicious content.

flowchart LR
    subgraph Raw["Raw Event Content"]
        TITLE["Issue Title"]
        BODY["Issue/PR Body"]
        COMMENT["Comment Text"]
    end

    subgraph Sanitization["Content Sanitization Pipeline"]
        direction TB
        MENTIONS["@mention Neutralization
@user → `@user`"] BOTS["Bot Trigger Protection
fixes #123 → `fixes #123`"] XML["XML/HTML Tag Conversion
<script> → (script)"] URI["URI Filtering
Only HTTPS from trusted domains"] SPECIAL["Special Character Handling
Unicode normalization"] LIMIT["Content Limits
0.5MB max, 65k lines"] CONTROL["Control Character Removal
ANSI escapes stripped"] end subgraph Safe["Sanitized Output"] SAFE_TEXT["needs.activation.outputs.text
✅ Safe for AI consumption"] end TITLE --> MENTIONS BODY --> MENTIONS COMMENT --> MENTIONS MENTIONS --> BOTS BOTS --> XML XML --> URI URI --> SPECIAL SPECIAL --> LIMIT LIMIT --> CONTROL CONTROL --> SAFE_TEXT

Sanitization Mechanisms:

MechanismInputOutputProtection
@mention Neutralization@user`@user`Prevents unintended user notifications
Bot Trigger Protectionfixes #123`fixes #123`Prevents automatic issue linking
XML/HTML Tag Conversion<script>(script)Prevents injection via XML tags
URI Filteringhttp://evil.com(redacted)Only HTTPS from trusted domains allowed
Special CharactersUnicode homoglyphsNormalizedPrevents visual spoofing attacks
Content LimitsLarge payloadsTruncated0.5MB max size, 65k lines max
Control CharactersANSI escapesStrippedRemoves terminal manipulation codes

URL Filtering Details:

The URI filtering mechanism applies strict validation:

  • Allowed: https://github.com/..., https://api.github.com/...
  • Allowed: URLs from explicitly trusted domains
  • Blocked: http:// URLs (non-HTTPS)
  • Blocked: URLs with suspicious patterns
  • Blocked: Data URLs, javascript: URLs
  • Blocked: URLs from untrusted domains → replaced with (redacted)

XML/HTML Tag Handling:

XML and HTML tags are converted to a safe parentheses format to prevent injection:

<script>alert('xss')</script> → (script)alert('xss')(/script)
<img src=x onerror=...> → (img src=x onerror=...)
<!-- hidden comment --> → (!-- hidden comment --)

Before workflow artifacts are uploaded, all files in the /tmp/gh-aw directory are automatically scanned and any secret values are redacted. This prevents accidental secret leakage through logs, outputs, or artifacts.

flowchart LR
    subgraph Sources["Secret Sources"]
        YAML["Workflow YAML"]
        ENV["Environment Variables"]
        MCP_CONF["MCP Server Config"]
    end

    subgraph Collection["Secret Collection"]
        SCAN["Scan for secrets.* patterns"]
        EXTRACT["Extract secret names:
SECRET_NAME_1
SECRET_NAME_2"] end subgraph Redaction["Secret Redaction Step"] direction TB FIND["Find files in /tmp/gh-aw
(.txt, .json, .log, .md, .yml)"] MATCH["Match exact secret values"] REPLACE["Replace with masked value:
abc***** (first 3 chars + asterisks)"] end subgraph Output["Safe Artifacts"] LOGS["Redacted Logs"] JSON_OUT["Sanitized JSON"] PROMPT["Clean Prompt Files"] end YAML --> SCAN ENV --> SCAN MCP_CONF --> SCAN SCAN --> EXTRACT EXTRACT --> FIND FIND --> MATCH MATCH --> REPLACE REPLACE --> LOGS REPLACE --> JSON_OUT REPLACE --> PROMPT

Key Features:

  • Automatic Detection: Scans workflow YAML for secrets.* patterns and collects all secret references
  • Exact String Matching: Uses safe string matching (not regex) to prevent injection attacks
  • Partial Visibility: Shows first 3 characters followed by asterisks for debugging without exposing full secrets
  • Custom Masking: Supports additional custom secret masking steps via secret-masking: configuration

Configuration Example:

secret-masking:
steps:
- name: Redact custom patterns
run: |
find /tmp/gh-aw -type f -exec sed -i 's/password123/REDACTED/g' {} +

The complete workflow execution follows a strict dependency order, ensuring security checks happen at each stage.

flowchart TB
    subgraph PreActivation["Pre-Activation Job"]
        ROLE["Role Permission Check"]
        DEADLINE["Stop-After Deadline"]
        SKIP["Skip-If-Match Check"]
        COMMAND["Command Position Validation"]
    end

    subgraph Activation["Activation Job"]
        CONTEXT["Prepare Workflow Context"]
        SANITIZE["Sanitize Event Text"]
        LOCK_CHECK["Validate Lock File"]
    end

    subgraph Agent["Agent Job"]
        CHECKOUT["Repository Checkout"]
        RUNTIME["Runtime Setup
(Node.js, Python)"] CACHE_RESTORE["Cache Restore"] MCP_START["Start MCP Containers"] PROMPT["Generate Prompt"] EXECUTE["Execute AI Engine"] REDACT["🔐 Secret Redaction"] UPLOAD["Upload Output Artifact"] CACHE_SAVE["Save Cache"] end subgraph Detection["Detection Job"] DOWNLOAD_DETECT["Download Artifact"] ANALYZE["AI + Custom Analysis"] VERDICT["Security Verdict"] end subgraph SafeOutputs["Safe Output Jobs"] CREATE_ISSUE["create_issue"] ADD_COMMENT["add_comment"] CREATE_PR["create_pull_request"] end subgraph Conclusion["Conclusion Job"] AGGREGATE["Aggregate Results"] SUMMARY["Generate Summary"] end ROLE --> DEADLINE DEADLINE --> SKIP SKIP --> COMMAND COMMAND -->|"✅ Pass"| CONTEXT COMMAND -->|"❌ Fail"| SKIP_ALL["Skip All Jobs"] CONTEXT --> SANITIZE SANITIZE --> LOCK_CHECK LOCK_CHECK --> CHECKOUT CHECKOUT --> RUNTIME RUNTIME --> CACHE_RESTORE CACHE_RESTORE --> MCP_START MCP_START --> PROMPT PROMPT --> EXECUTE EXECUTE --> REDACT REDACT --> UPLOAD UPLOAD --> CACHE_SAVE CACHE_SAVE --> DOWNLOAD_DETECT DOWNLOAD_DETECT --> ANALYZE ANALYZE --> VERDICT VERDICT -->|"✅ Safe"| CREATE_ISSUE VERDICT -->|"✅ Safe"| ADD_COMMENT VERDICT -->|"✅ Safe"| CREATE_PR VERDICT -->|"❌ Threat"| BLOCK_ALL["Block All Safe Outputs"] CREATE_ISSUE --> AGGREGATE ADD_COMMENT --> AGGREGATE CREATE_PR --> AGGREGATE AGGREGATE --> SUMMARY

GitHub Agentic Workflows provide comprehensive observability through GitHub Actions runs and artifacts, enabling debugging, auditing, and cost monitoring.

flowchart TB
    subgraph Workflow["Workflow Execution"]
        RUN["GitHub Actions Run"]
        JOBS["Job Logs"]
        STEPS["Step Outputs"]
    end

    subgraph Artifacts["Workflow Artifacts"]
        AGENT_OUT[/"agent_output.json
AI decisions & actions"/] PROMPT[/"prompt.txt
Generated prompts"/] PATCH[/"aw.patch
Code changes"/] LOGS[/"engine logs
Token usage & timing"/] FIREWALL[/"firewall logs
Network requests"/] end subgraph CLI["CLI Tools"] AW_LOGS["gh aw logs
Download & analyze runs"] AW_AUDIT["gh aw audit
Investigate failures"] AW_STATUS["gh aw status
Workflow health"] end subgraph Insights["Observability Insights"] COST["💰 Cost Tracking
Token usage per run"] DEBUG["🔍 Debugging
Step-by-step trace"] SECURITY["🛡️ Security Audit
Network & tool access"] PERF["⚡ Performance
Duration & bottlenecks"] end RUN --> JOBS JOBS --> STEPS STEPS --> Artifacts AGENT_OUT --> AW_LOGS PROMPT --> AW_LOGS PATCH --> AW_AUDIT LOGS --> AW_LOGS FIREWALL --> AW_AUDIT AW_LOGS --> COST AW_LOGS --> PERF AW_AUDIT --> DEBUG AW_AUDIT --> SECURITY AW_STATUS --> DEBUG

Key Observability Features:

  • Artifact Preservation: All workflow outputs (prompts, patches, logs) are saved as downloadable artifacts
  • Cost Monitoring: Track token usage and costs across workflow runs with gh aw logs
  • Failure Analysis: Investigate failed runs with gh aw audit to see prompts, errors, and network activity
  • Firewall Logs: Review all network requests made by the agent for security auditing
  • Step Summaries: Rich markdown summaries in GitHub Actions showing AI decisions and outputs

CLI Commands:

# Download and analyze workflow run logs
gh aw logs
# Investigate a specific workflow run
gh aw audit <run-id>
# Check workflow health and status
gh aw status
LayerMechanismProtection Against
CompilationSchema validation, expression allowlistInvalid configurations, unauthorized expressions
CompilationAction SHA pinningSupply chain attacks, tag hijacking
CompilationSecurity scanners (actionlint, zizmor, poutine)Privilege escalation, misconfigurations, supply chain risks
RuntimePre-activation checksUnauthorized users, expired workflows
RuntimeContent sanitizationPrompt injection, @mention abuse
RuntimeAWF network controlsData exfiltration, unauthorized API calls
RuntimeMCP sandboxingContainer escape, unauthorized tool access
RuntimeSecret redactionCredential leakage in logs/artifacts
OutputThreat detectionMalicious patches, secret leaks
OutputPermission separationDirect write access abuse
OutputOutput sanitizationContent injection, XSS
ObservabilityArtifact preservation, CLI toolsDebugging failures, auditing security, cost tracking