How to Audit Workflow Runs for Security Compliance and Tool Usage with gh-aw
The gh aw audit command inspects GitHub Actions runs, downloads artifacts, parses logs, and generates structured security compliance reports highlighting excessive permissions, template injection risks, and MCP tool usage.
To audit workflow runs for security compliance and tool usage, the github/gh-aw extension provides an offline-first analysis engine that resolves run identifiers, caches artifacts locally, and executes security validators against workflow definitions and execution logs. This article breaks down the architecture, security checks, and practical commands for comprehensive compliance auditing.
Core Architecture and Entry Points
NewAuditCommand and CLI Interface
The audit functionality begins in pkg/cli/audit.go where NewAuditCommand defines the CLI interface, registers flags, and binds execution to the AuditWorkflowRun function. This command accepts run IDs, run URLs, job URLs, or step URLs as positional arguments, enabling granular audits at the workflow, job, or step level.
AuditWorkflowRun Orchestration
The AuditWorkflowRun function (lines 28-63 in pkg/cli/audit.go) orchestrates the complete audit flow:
- Resolution: Parses input through
parser.ParseRunURLExtendedto extract run ID, job ID, and step numbers - Metadata Fetching: Retrieves run metadata from the GitHub API or falls back to local cache
- Artifact Download: Executes
downloadRunArtifactsto pull all workflow artifacts via the GitHub MCP server - Security Analysis: Analyzes logs for MCP tool usage, missing-tool reports, and performance metrics
- Report Rendering: Outputs results via
renderConsoleorrenderJSONbased on user flags
Security-Focused Validation Checks
Excessive Permissions Detection
The audit engine integrates with the Zizmor validator to detect workflows requesting overly broad permissions. When AuditWorkflowRun processes workflow definitions, it flags excessive-permissions issues—such as read/write access on the repository when read-only would suffice—and reports these under the Key Findings section with Medium severity ratings.
Template Injection Analysis
Located in pkg/workflow/template_injection_validation.go, the template injection validator scans for untrusted user input embedded in workflow strings and shell commands. The audit identifies template-injection risks where attacker-controlled values (like issue titles or branch names) could execute arbitrary code, marking these as High severity findings in the compliance report.
MCP Tool Usage and Firewall Analysis
The AuditData structure (defined in pkg/cli/audit_report_helpers.go) aggregates several security-relevant sections:
- MCP Server Failures: Captures tool-specific failure messages including sandbox violations and missing-tool errors
- Firewall Analysis: Summarizes outbound network requests blocked or allowed during workflow execution
- Redacted URL Domains: Lists domains stripped from logs for privacy compliance, ensuring no sensitive endpoints leak in audit trails
Offline-First Caching and Artifact Management
Artifact Download Strategy
The downloadRunArtifacts function in pkg/cli/artifact_download.go interfaces with the GitHub MCP server to retrieve all workflow artifacts. It handles ErrNoArtifacts gracefully when runs produce no artifacts, and stores downloads in a local directory structure organized by run ID.
Cache Detection Utilities
To support offline re-analysis, pkg/cli/fileutil/util.go provides DirExists and IsDirEmpty helpers. When AuditWorkflowRun detects existing cached artifacts via these utilities, it skips API calls and re-uses local data—mitigating permission errors and enabling air-gapped compliance reviews.
Report Generation and Output Formats
Console Rendering
The renderConsole function in pkg/cli/audit_report_render.go (lines 21-78) converts the AuditData struct into human-readable tables. It organizes output into sections: Overview, Key Findings, Recommendations, Failure Analysis, Performance Metrics, Job Tables, and Security Diagnostics.
JSON Output for Downstream Tooling
The renderJSON function produces machine-readable output suitable for CI/CD pipelines and security information event management (SIEM) systems. The JSON schema mirrors the AuditData structure, containing nested objects for overview metadata, findings arrays, and tool usage statistics.
AuditData Structure
Defined in pkg/cli/audit_report_helpers.go, the AuditData struct aggregates:
- Overview: Run ID, workflow name, status, duration, event type, branch, URLs
- Key Findings: Security issues with severity levels (excessive permissions, template injection)
- Recommendations: Actionable remediation steps
- Failure Analysis: Job and step-level failure breakdowns
- MCP Failures: Tool execution errors and sandbox violations
- Tool Usage: Statistics on MCP tool invocations
- Firewall/Domain Analysis: Network activity and privacy redactions
Practical Usage Examples
Audit a workflow run using its numeric ID:
gh aw audit 1234567890
Audit using a full GitHub Actions URL:
gh aw audit https://github.com/owner/repo/actions/runs/1234567890
Audit a specific job and step for granular analysis:
gh aw audit https://github.com/owner/repo/actions/runs/1234567890/job/9876543210#step:7:1
Store artifacts and reports in a custom directory with verbose logging:
gh aw audit 1234567890 -o ./my-audit --verbose
Generate machine-readable JSON for downstream security tools:
gh aw audit 1234567890 --json > audit-report.json
Summary
- The
gh aw auditcommand ingithub/gh-awprovides comprehensive workflow run analysis through theAuditWorkflowRunorchestrator inpkg/cli/audit.go. - Security compliance checks include excessive permissions detection, template injection validation via
pkg/workflow/template_injection_validation.go, and MCP tool misuse analysis. - Offline-first caching via
pkg/cli/fileutil/util.goenables re-analysis without API calls, usingDirExistsandIsDirEmptyto detect cached artifacts. - Flexible output formats support both human-readable console tables via
renderConsoleand machine-readable JSON viarenderJSONinpkg/cli/audit_report_render.go. - Granular auditing supports run IDs, URLs, job URLs, and step URLs through
parser.ParseRunURLExtendedinpkg/parser/run_url.go.
Frequently Asked Questions
What security issues does gh aw audit detect?
The audit command detects excessive permissions (workflows requesting broader access than necessary), template injection vulnerabilities (untrusted user input in workflow strings), and MCP tool misuse (sandbox violations and missing-tool errors). These checks are implemented in pkg/workflow/template_injection_validation.go and reported through the AuditData structure in pkg/cli/audit_report_helpers.go.
Can I audit workflow runs without internet access?
Yes. The tool implements an offline-first architecture using cache detection utilities in pkg/cli/fileutil/util.go. If you have previously audited a run, the DirExists and IsDirEmpty functions detect cached artifacts in the local directory, allowing AuditWorkflowRun to re-analyze logs and generate reports without calling the GitHub API.
How do I integrate audit results into CI/CD pipelines?
Use the --json flag to produce machine-readable output suitable for downstream tooling. The renderJSON function in pkg/cli/audit_report_render.go outputs a structured document containing the AuditData schema, including severity-rated findings, recommendations, and tool usage statistics. Redirect this output to a file or pipe it directly into security information event management (SIEM) systems.
What input formats does the audit command accept?
The command accepts numeric run IDs, run URLs, job URLs, and step URLs through the parser.ParseRunURLExtended function in pkg/parser/run_url.go. This flexibility allows you to audit entire workflow runs or drill down to specific jobs and steps by providing URLs copied directly from the GitHub Actions web interface.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →