Back to skill

Security audit

GitHub Actions Timeout Risk Audit

Security checks for vulnerabilities and agentic risk

Overview

This skill locally analyzes GitHub Actions run exports for timeout risk, with only a minor text-output spoofing concern for untrusted report data.

This is reasonable to install for auditing CI timeout risk. Run it only against intended GitHub Actions export files, and prefer OUTPUT_FORMAT=json or trusted input data when logs may include untrusted workflow or job names.

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

Note
Location
scripts/timeout-risk-audit.sh:345
Finding

Unescaped Terminal Control Characters Allow CI Log and Terminal Output Spoofing

Content
View full analysis

Vulnerability Details

File Location: scripts/timeout-risk-audit.sh, lines 345–350
Vulnerability Type: Untrusted terminal and CI-log output
Risk Level: Low

Vulnerable Code

python
for row in ranked_groups[:top_n]:
    print(
        f"- [{row['severity']}] {row['repository']} :: {row['workflow']} :: {row['job_name']} "
        f"max_duration_s={row['max_duration_seconds']} avg_duration_s={row['avg_duration_seconds']} "
        f"critical={row['critical_count']} warn={row['warn_count']} timed_out={row['timed_out_count']} "
        f"instances={row['instances']}"
    )

Technical Analysis

The repository, workflow, and job_name values originate from imported GitHub Actions run JSON. They are interpolated directly into text output without escaping terminal control characters.

JSON decoding preserves encoded control characters such as escape (\u001b), carriage return (\r), and newline (\n). If an attacker can influence workflow or job metadata, crafted values can inject ANSI escape sequences or additional log lines. A terminal or CI log renderer may interpret these sequences rather than displaying them literally.

This issue affects text output. JSON output uses json.dumps, which escapes control characters and is not affected in the same way.

Attack Path

  1. An attacker who can modify workflow metadata creates a workflow or job name containing encoded terminal control characters.
  2. GitHub Actions produces a run containing the crafted metadata.
  3. The run is exported to JSON and included in a path matched by RUN_GLOB.
  4. The audit script parses the attacker-controlled value and stores it without sanitization.
  5. The script runs with OUTPUT_FORMAT=text.
  6. The crafted value is printed directly to a terminal or CI log.
  7. The renderer interprets the control sequence, potentially hiding findings, changing visible terminal content, or injecting misleading log entries.

Impact Assessment

The issue can compromi ...[truncated 403 chars]

Remediation
View remediation

Remediation Suggestions

Sanitize every untrusted value before writing text-mode output:

  1. Replace C0 and C1 control characters with visible escaped representations.
  2. At minimum, escape escape characters, carriage returns, newlines, backspaces, tabs, and delete characters.
  3. Apply the sanitizer consistently to repository names, workflow names, job names, branches, URLs, file paths, and parse-error messages.
  4. Preserve JSON mode, where json.dumps already encodes control characters safely.
  5. Add regression tests using values containing \u001b[2J, \r, and \n.

For example:

python
def sanitize_text(value):
    text = str(value)
    return ''.join(
        ch if ch.isprintable() and ch not in '\r\n'
        else f'\\x{ord(ch):02x}'
        for ch in text
    )

Use the sanitized values in all text-report print calls:

python
repository = sanitize_text(row['repository'])
workflow = sanitize_text(row['workflow'])
job_name = sanitize_text(row['job_name'])

print(
    f"- [{row['severity']}] {repository} :: {workflow} :: {job_name} "
    f"max_duration_s={row['max_duration_seconds']} "
    f"avg_duration_s={row['avg_duration_seconds']} "
    f"critical={row['critical_count']} warn={row['warn_count']} "
    f"timed_out={row['timed_out_count']} instances={row['instances']}"
)
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

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.