Back to skill

Security audit

GitHub Actions Permission Scope Audit

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent local GitHub Actions audit skill, but its own parser can miss valid workflow syntax while offering CI gate behavior.

Install only if you treat this as a lightweight triage helper, not a complete security control. It does not appear to steal data or modify repositories, but users relying on FAIL_ON_CRITICAL for CI enforcement should review or replace the YAML parsing before trusting gate results.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/permission-scope-audit.sh:104
Finding
Valid YAML Syntax Can Bypass Permission-Risk Detection## Vulnerability Details **File Location**: `scripts/permission-scope-audit.sh`, lines 104–175 **Vulnerability Type**: Incomplete security analysis caused by regex-based YAML parsing **Risk Level**: Medium ### Vulnerable Code ```python def extract_event_set(lines): events = set() in_on = False on_indent = -1 for line in lines: stripped = line.strip() if not stripped or stripped.startswith('#'): continue indent = len(line) - len(line.lstrip(' ')) if re.match(r'^on\s*:\s*$', line): in_on = True on_indent = indent continue if in_on: if indent <= on_indent and stripped: in_on = False else: match = trigger_key_re.match(stripped) if match: events.add(match.group(1)) return sorted(events) ``` ```python if re.match(r'^\s*permissions\s*:\s*$', line): permissions_blocks += 1 in_permissions = True permission_indent = indent continue if in_permissions and indent <= permission_indent and stripped: in_permissions = False if in_permissions: write_match = write_scope_re.match(line) if write_match: scope = write_match.group(1) permission_entries.append( {'line': idx, 'scope': scope, 'value': 'write'} ) continue inline_match = re.match( r'^\s*permissions\s*:\s*([^#]+?)\s*(?:#.*)?$', line ) if inline_match: value = inline_match.group(1).strip().strip('"\'') lowered = value.lower() if lowered in {'write-all', 'read-all'}: permission_entries.append( {'line': idx, 'scope': lowered, 'value': lowered} ) ``` ### Technical Analysis The security scanner interprets GitHub Actions workflow YAML through line-oriented regular expressions rather than a YAML parser. Trigger extraction only recognizes a bare block-form `on:` key followed by separately indented event keys ...[truncated 2693 chars]
Remediation
## Remediation Suggestions 1. Replace line-oriented regular-expression parsing with a maintained YAML parser. 2. Parse and normalize the workflow-level and job-level `permissions` nodes, supporting: - Block mappings - Flow mappings - Scalar `read-all` and `write-all` values - Empty mappings and `permissions: {}` - Quoted keys and values 3. Normalize the `on` node across all valid representations: - Scalar events - Event lists - Block mappings - Flow mappings 4. Ensure YAML 1.1 boolean coercion does not incorrectly convert the GitHub Actions key `on`; use a loader with suitable YAML semantics or explicitly account for this behavior. 5. Treat malformed YAML, unsupported node types, and parser failures as policy-gate failures when enforcement mode is enabled. 6. Add regression fixtures covering at least: ```yaml on: pull_request_target permissions: write-all ``` ```yaml on: [pull_request_target] permissions: {contents: write} ``` ```yaml "on": pull_request_target: "permissions": contents: write ``` 7. Test workflow-level and job-level permissions separately, including cases where job permissions override or restrict workflow defaults. 8. Add an automated assertion that each dangerous fixture produces the expected critical classification and a nonzero exit status when `FAIL_ON_CRITICAL=1`.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (4)

Context-Inappropriate Capability

Critical
Confidence
100% confidence
Finding
`pull_request_target` runs in the security context of the target repository, and combining it with `write-all` gives untrusted pull request activity access to a highly privileged token. In an audit-focused workflow this capability is unjustified and could enable repository modification, secret abuse, workflow tampering, or persistence if the workflow is later expanded or influenced by attacker-controlled PR content.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The workflow grants `write-all` repository permissions even though its stated purpose is only to audit GitHub Actions permission scope. Excessive token privileges violate least privilege and create a broad blast radius if any step, dependency, or future modification is compromised.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
This workflow grants `contents: write` at the top level even though the only job shown performs a checkout and an `echo`, which do not require repository write access. In a permission-scope audit skill, requesting broader token privileges than necessary increases the blast radius if the workflow or an invoked action is compromised, enabling unintended repository modifications.

Static analysis

No suspicious patterns detected.