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

Content
View full analysis

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
View 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
  1. Test workflow-level and job-level permissions separately, including cases where job permissions override or restrict workflow defaults.
  2. 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
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.