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:

  1. Resolution: Parses input through parser.ParseRunURLExtended to extract run ID, job ID, and step numbers
  2. Metadata Fetching: Retrieves run metadata from the GitHub API or falls back to local cache
  3. Artifact Download: Executes downloadRunArtifacts to pull all workflow artifacts via the GitHub MCP server
  4. Security Analysis: Analyzes logs for MCP tool usage, missing-tool reports, and performance metrics
  5. Report Rendering: Outputs results via renderConsole or renderJSON based 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 audit command in github/gh-aw provides comprehensive workflow run analysis through the AuditWorkflowRun orchestrator in pkg/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.go enables re-analysis without API calls, using DirExists and IsDirEmpty to detect cached artifacts.
  • Flexible output formats support both human-readable console tables via renderConsole and machine-readable JSON via renderJSON in pkg/cli/audit_report_render.go.
  • Granular auditing supports run IDs, URLs, job URLs, and step URLs through parser.ParseRunURLExtended in pkg/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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →