Back to skill

Security audit

Github Growth Tracker

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate GitHub stats tracker, but users should avoid the token-saving setup path unless they accept plaintext local token storage.

Install only if you are comfortable granting GitHub API read access for repo metrics. Prefer setting GITHUB_TOKEN through your agent or shell instead of passing --token, and use a fine-grained public-repository read-only token; do not provide a broader token unless you accept the increased impact if the local credential file, shell history, or logs are exposed.

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/github_tracker.py:69
Finding

GitHub Personal Access Token Exposed Through Command-Line Arguments and Plaintext Storage

Content
View full analysis
/github.json.""" creds_dir = os.path.dirname(CREDENTIALS_PATH) os.makedirs(creds_dir, exist_ok=True) with open(CREDENTIALS_PATH, "w") as f: json.dump({"github_token": token}, f, indent=2) f.write("\n") os.chmod(CREDENTIALS_PATH, 0o600) ``` `scripts/github_tracker.py:406`: ```python s.add_argument("--token", help="GitHub PAT (saved to /github.json)") ``` `SKILL.md:35-42`: ```markdown Pass via `setup --token ` (saved to `/github.json`) or set `GITHUB_TOKEN` env var. ⚠ Token is stored plaintext on disk. For higher security, use the `GITHUB_TOKEN` environment variable instead. ## Setup ``` python3 scripts/github_tracker.py setup --token # list your repos ``` ``` ### Technical Analysis The setup workflow accepts a GitHub personal access token directly through a command-line argument and then stores that token unencrypted in `github.json`. Command-line credentials can be exposed through shell history, process inspection facilities, terminal logs, agent execution logs, or command auditing systems. Persisting the token as JSON creates an additional long-lived secret disclosure surface. The file permission is changed to `0600`, which appropriately limits access by other operating-system users, but it does not protect the token from processes running under the same account, compromised user-level applications, plaintext backups, or accidental copying. The token is transmitted only in an `Authorization` header to the fixed HTTPS origin `https://api.github.com`. Repository names affect only the request path and cannot change t ...[truncated 2013 chars]
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (12)

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 · SKILL.md (reported line 28)May include surrounding context.

Credentials

Required: GitHub Personal Access Token (fine-grained, public repo read-only).

text
Create at: github.com → Settings → Developer settings → Personal access tokens

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 · SKILL.md (reported line 31)May include surrounding context.

Required: GitHub Personal Access Token (fine-grained, public repo read-only).

text
Create at: github.com → Settings → Developer settings → Personal access tokens
Type:     Fine-grained
Access:   Public repos (read-only)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises capabilities that include environment access, file writes, network access, and shell execution, but it does not declare any explicit tool scope or permission boundaries. In an agent ecosystem, this increases the chance of over-broad execution or unsafe invocation because the platform and user are not given clear constraints on what the skill is allowed to access or do.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The top-level description uses broad GitHub-monitoring language that can match many ordinary user requests, increasing the chance the skill is auto-invoked outside the user's precise intent. Over-broad activation is dangerous because this skill can access credentials, write files, and perform networked actions once selected.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The 'When to Use' examples are vague and do not include constraints or disambiguation, so the skill may be invoked for broad requests like checking repo stats or comparing repos without confirming scope or authorization. In context, that matters because invocation could lead to token handling, outbound requests, and local persistence.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
97% confidence
Finding

The skill explicitly states that the token may be passed via setup and then saved to '<DATA_DIR>/github.json', and it warns that the token is stored in plaintext on disk. Persisting an API token unencrypted creates a clear secret exposure risk if the host is shared, backups are accessed, logs leak file contents, or other local processes can read the data directory.

Content

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

Required: GitHub Personal Access Token (fine-grained, public repo read-only).

text
Create at: github.com → Settings → Developer settings → Personal access tokens
Type:     Fine-grained
Access:   Public repos (read-only)

Context Window Stuffing

Medium
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Content

Scanner excerpt · references/formatting.md (reported line 23)May include surrounding context.

md
> `TypeScript` · Last push: 2026-04-03
> vs watchlist: ✅ above avg commit velocity

_· · · · · · · · · · · · · · · · · · · · · · · · · · ·_

📌 *Watchlist*

Tainted flow: 'CREDENTIALS_PATH' from os.environ.get (line 34, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/github_tracker.py (reported line 73)May include surrounding context.

python
"""Save token to <DATA_DIR>/github.json."""
    creds_dir = os.path.dirname(CREDENTIALS_PATH)
    os.makedirs(creds_dir, exist_ok=True)
    with open(CREDENTIALS_PATH, "w") as f:
        json.dump({"github_token": token}, f, indent=2)
        f.write("\n")
    os.chmod(CREDENTIALS_PATH, 0o600)

Tainted flow: 'CONFIG_PATH' from os.environ.get (line 32, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/github_tracker.py (reported line 94)May include surrounding context.

python
def save_config(cfg):
    _ensure_dirs()
    with open(CONFIG_PATH, "w") as f:
        json.dump(cfg, f, indent=2)
        f.write("\n")

Tainted flow: 'REPOS_DIR' from os.environ.get (line 33, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/github_tracker.py (reported line 117)May include surrounding context.

python
# Trim history to MAX_HISTORY_DAYS
    cutoff = (date.today() - timedelta(days=MAX_HISTORY_DAYS)).isoformat()
    data["history"] = [h for h in data["history"] if h.get("date", "") >= cutoff]
    with open(os.path.join(REPOS_DIR, f"{_rkey(repo)}.json"), "w") as f:
        json.dump(data, f, indent=2)
        f.write("\n")

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The setup command enumerates all repositories owned by the authenticated user via /user/repos, which collects broader account data than is necessary to track explicitly specified repos and watchlists. In an agent skill context, this expands data access and may surprise users or violate least-privilege expectations, especially if the manifest implies narrower functionality.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The save_token docstring says the token is saved to <DATA_DIR>/github.json, but CREDENTIALS_PATH is constructed independently from SKILL_DATA_DIR rather than from DATA_DIR. If DATA_DIR is changed by fallback or future refactoring, the documented storage location can diverge from the actual credential path.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.