Back to skill

Security audit

Copilot Usage

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its Copilot usage-reporting purpose, but one alert script has a real command-execution vulnerability that users should review before installing.

Review or patch scripts/copilot-alert.sh before installing or using the alert command, especially in automation. The usage dashboard behavior is mostly disclosed, but this skill requires a classic GitHub token via gh with billing-related scopes and writes a local plan/quota config file, so only use it where that access is acceptable.

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

Error
Location
scripts/copilot-alert.sh:51
Finding

Arbitrary Python Code Injection Through Unquoted Heredoc Interpolation

Content
View full analysis

Vulnerability Details

File Location: scripts/copilot-alert.sh, lines 51–64
Vulnerability Type: Python source injection through unsafe shell-variable interpolation
Risk Level: High

Vulnerable Code

bash
python3 << PYEOF
import json, sys, datetime

data = json.loads(r"""$DATA""")
items = data.get("usageItems", [])
total_included = sum(i["discountQuantity"] for i in items)
total_overage  = sum(i["netQuantity"] for i in items)
total_cost     = sum(i["netAmount"] for i in items)
quota          = $QUOTA
plan           = "$PLAN_NAME"
threshold      = $THRESHOLD

Technical Analysis

The script uses an unquoted heredoc delimiter, causing the shell to expand $DATA, $QUOTA, $PLAN_NAME, and $THRESHOLD directly into executable Python source.

These values cross trust boundaries without syntactic escaping or type validation:

  • $THRESHOLD comes directly from the --threshold command-line argument.
  • $QUOTA and $PLAN_NAME are read from the user-writable ~/.config/copilot-usage/config.json file.
  • $DATA contains the GitHub API response and is inserted into a triple-quoted Python string.

An attacker-controlled value can terminate its intended Python expression and append arbitrary Python statements. For example, a threshold value conceptually shaped as:

text
0; import os; os.system("attacker-command"); #

produces executable Python resembling:

python
threshold = 0; import os; os.system("attacker-command"); #

Similar injection is possible through a crafted plan name that closes the surrounding quoted string. The API response is also not safely transported: a value containing the relevant triple-quote sequence could escape the json.loads string literal.

The vulnerability is caused by generating source code from data rather than passing data through a non-executable channel such as standard input, a temporary file, environment variables, or ...[truncated 1711 chars]

Remediation
View remediation

Remediation Suggestions

  1. Use a quoted heredoc delimiter so the shell cannot interpolate data into Python source:

    bash
    python3 - "$QUOTA" "$PLAN_NAME" "$THRESHOLD" <<'PYEOF'
    import json
    import sys
    
    quota = int(sys.argv[1])
    plan = sys.argv[2]
    threshold = int(sys.argv[3])
    data = json.load(sys.stdin)
    PYEOF
    

    Because both the program and JSON cannot conveniently occupy the same standard-input stream, prefer storing the API response in a securely created temporary file and passing its path through sys.argv, as already done by copilot-usage.sh.

  2. A safe implementation pattern is:

    bash
    TMP_FILE=$(mktemp "${TMPDIR:-/tmp}/copilot-alert.XXXXXX")
    trap 'rm -f "$TMP_FILE"' EXIT
    
    gh api \
      -H "Accept: application/vnd.github+json" \
      -H "X-GitHub-Api-Version: 2022-11-28" \
      "/users/${GH_USER}/settings/billing/premium_request/usage" \
      > "$TMP_FILE"
    
    python3 - "$TMP_FILE" "$QUOTA" "$PLAN_NAME" "$THRESHOLD" <<'PYEOF'
    import json
    import sys
    
    data_path, quota_raw, plan, threshold_raw = sys.argv[1:]
    quota = int(quota_raw)
    threshold = int(threshold_raw)
    
    with open(data_path, encoding="utf-8") as handle:
        data = json.load(handle)
    PYEOF
    
  3. Validate --threshold before any network request or Python invocation. Require a decimal integer and enforce a documented range such as 0–100.

  4. Validate configuration after loading it:

    • Require quota to be a positive bounded integer.
    • Require plan to match the existing plan allowlist.
    • Reject malformed JSON and unexpected data types with a clear error.
  5. Quote temporary-file variables in traps and other shell operations. Avoid constructing executable source code from API responses, configuration fields, or command-line arguments under all circumstances.

Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
Findings (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description promises a broad Copilot usage/billing reporting tool that shows quota, billing stats, remaining premium requests, which models were used, and per-model multipliers. The supplied code instead implements a narrow alert script: it authenticates with gh, reads a manually configured quota and plan from ~/.config/copilot-usage/config.json, fetches aggregate premium request usage from one billing endpoint, computes usage percentage and overage, and prints either an OK or warning message. It does not display model usage, per-model multipliers, or a rich usage dashboard/report. The main behavior is threshold monitoring with alerting and exit codes, which is materially narrower and somewhat different from the declared purpose.

Content

No source excerpt is available for this finding.

External Model or Provider Selection

High
Category
Excessive Agency
Confidence
90% confidence
Finding

Skill selects an external model or provider that may use a different account or billing plan than the operator expects. Undisclosed model switches can cause unexpected cost or quota consumption.

Content

Scanner excerpt · SKILL.md (reported line 32)May include surrounding context.

bash
bash scripts/copilot-usage.sh                        # current month
bash scripts/copilot-usage.sh --month 3 --year 2026  # specific month
bash scripts/copilot-usage.sh --model claude          # filter by model
bash scripts/copilot-usage.sh --json                  # raw JSON output
bash scripts/copilot-usage.sh --set-plan pro+         # configure plan
bash scripts/copilot-alert.sh --threshold 80          # quota alert check

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/api.md (reported line 14)May include surrounding context.

md
## Auth Requirements

- **Token type**: Personal Access Token (classic) — fine-grained tokens NOT supported
- **Required scopes**: `manage_billing:copilot` + `user`
- Usage: `gh api ...` (inherits `gh auth` automatically)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill instructs use of network-capable tooling (gh CLI and GitHub REST API) but does not declare any explicit tool scope or allowed-tools boundary. This creates an authorization and review gap: an agent may invoke network access and authenticated billing endpoints without a clear least-privilege declaration, increasing the chance of unintended external calls or misuse of sensitive tokens.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest describes a read-oriented usage dashboard/reporting skill, but the script includes a separate configuration-writing mode that creates ~/.config/copilot-usage/config.json and stores plan/quota data. Writing local state to alter later reporting is broader than simply displaying usage and billing stats, and this capability is not disclosed in the manifest description.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

For a skill presented as showing Copilot usage, quota, billing stats, and model multipliers, adding a mode that writes plan information to a user config file is an extra capability not obviously required by that purpose. The dashboard could instead report API data and note unknown quota without persisting state.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.