Back to skill

Security audit

review-github-pr

Security checks for vulnerabilities and agentic risk

Overview

This PR-review skill mostly matches its stated purpose, but it needs review because one posting step uses a predictable temporary file that could let local tampering change an authenticated GitHub review.

Use this only if you are comfortable giving the agent access to the target repository and your active GitHub CLI credentials. Before posting reviews, replace the fixed /tmp/pr-review.json workflow with mktemp or stdin piping, verify the final repository and review action, and remove temporary payloads after submission.

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
SKILL.md:220
Finding

Predictable temporary review file permits symlink overwrite and review-payload tampering

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:220-242
Vulnerability Type: Predictable unsafe temporary file
Risk Level: Medium

Vulnerable Code

bash
cat > /tmp/pr-review.json <<'EOF'
{
  "event": "REQUEST_CHANGES",
  "body": "1 critical, 1 minor - details inline on the diff.",
  "comments": [
    {
      "path": "src/main.rs",
      "line": 1653,
      "side": "RIGHT",
      "body": "[Correctness] `fmt::layer()` defaults to stdout, moving all tracing output onto the JSON-RPC channel.\n\n```suggestion\n        .with(fmt::layer().with_writer(std::io::stderr))\n```"
    },
    {
      "path": "src/main.rs",
      "start_line": 1651,
      "line": 1654,
      "side": "RIGHT",
      "body": "[Convention] The stderr choice deserves a WHY comment - it is the only thing keeping stdout clean for JSON-RPC."
    }
  ]
}
EOF
gh api repos/{owner}/{repo}/pulls/<number>/reviews --input /tmp/pr-review.json

Technical Analysis

The skill instructs the agent to create a sensitive API request payload at the fixed, globally predictable path /tmp/pr-review.json. Shell output redirection normally follows symbolic links and does not create the file atomically with exclusive ownership checks.

A local attacker able to manipulate that path may exploit two distinct time-of-check/time-of-use opportunities:

  1. Before redirection, the attacker can place a symbolic link at /tmp/pr-review.json. The shell may then truncate and overwrite the link target with the review JSON.
  2. After the heredoc finishes but before gh api opens the file, the attacker can replace or alter the predictable file. The GitHub CLI would then transmit attacker-controlled review content using the victim's authenticated GitHub credentials.

Common Linux protections such as fs.protected_symlinks and sticky-directory ownership restrictions can reduce cross-user exploitation, but they are platform-d ...[truncated 2693 chars]

Remediation
View remediation

Remediation Suggestions

Replace the fixed filename with a securely and atomically created temporary file, restrict its permissions, pass the exact generated path to gh, and guarantee cleanup:

bash
review_file="$(mktemp "${TMPDIR:-/tmp}/pr-review.XXXXXXXX.json")" || exit 1
chmod 600 "$review_file"
trap 'rm -f -- "$review_file"' EXIT HUP INT TERM

cat > "$review_file" <<'EOF'
{
  "event": "REQUEST_CHANGES",
  "body": "1 critical, 1 minor - details inline on the diff.",
  "comments": []
}
EOF

gh api "repos/{owner}/{repo}/pulls/<number>/reviews" --input "$review_file"

Additional hardening should include:

  • Prefer piping the generated payload directly to gh api --input - if supported, eliminating the temporary file.
  • Generate JSON with a structured serializer such as jq rather than interpolating untrusted strings into a heredoc.
  • Keep the existing explicit user-confirmation requirement before transmission.
  • Validate the final repository, pull-request number, review event, and payload summary immediately before submission.
  • Avoid printing tokens or authenticated command environments in logs.
  • Ensure cleanup occurs on successful completion, errors, and interruption.
  • If a temporary file must be reopened, verify that it remains a regular file owned by the current user and has not been replaced before submission.
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 (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description is for an operational PR-review skill that analyzes an actual GitHub pull request and drafts review comments. The supplied code does not review a PR at all. Instead, it is a test fixture setup script used to simulate a clean PR scenario: it initializes a repository, creates base and feature-branch code, computes a diff, installs a mock gh command, and outputs instructions for running the fixture. This is a materially different primary purpose and includes undeclared capabilities related to repository creation, branch manipulation, and command mocking.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description says the skill reviews GitHub pull requests end to end. However, this code does not implement review logic, run checks, perform multi-agent analysis, validate findings, or draft inline comments. Its actual purpose is to build a local fixture repository with intentional bugs and conventions violations for testing such a reviewer. The mock gh CLI only emits canned responses and does not represent genuine PR review behavior. This is a materially different primary purpose and includes undeclared repository/file-system setup capabilities.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description is for a PR review skill that analyzes an existing GitHub pull request. This code chunk instead is a test/setup script for an evaluation fixture. Its primary purpose is to create a sample repository with intentional efficiency/design issues and mock out gh responses. While it tangentially relates to PR review testing, it does not itself fetch a real PR, run review checks, perform three-agent analysis, validate findings, or draft comments. The behavior is materially different from the declared purpose and includes undeclared file-system and git-repository setup capabilities.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill invokes shell and network-capable tools (gh, git, cloning, checkout, API posting) but does not declare any explicit tool scope such as permissions or allowed-tools. That creates an authorization gap where a host agent may grant broader capabilities than reviewers expect, increasing the chance of unintended command execution, repo mutation, or outbound requests when handling untrusted PR content.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · evals/fixtures/correctness-convention/setup.sh (reported line 188)May include surrounding context.

sh
http.Error(w, "internal error", http.StatusInternalServerError)
		return
	}
	// Bug: ticket can be nil if not found, but we access .Title without checking
	response := map[string]interface{}{
		"id":       ticket.ID,
		"title":    ticket.Title,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This setup script immediately creates a temporary repository, changes directories, initializes git, and later writes many files and an executable helper script. Although comments describe what the fixture does, there is no user-facing warning, prompt, or explicit disclosure in the script output before these state-changing operations begin.

Content

No source excerpt is available for this finding.

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · LICENSE.txt (reported line 27)May include surrounding context.

text
permissions granted by this License.

"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation source, and
configuration files.

"Object" form shall mean any form resulting from mechanical transformation or

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · LICENSE.txt (reported line 31)May include surrounding context.

text
permissions granted by this License.

"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation source, and
configuration files.

"Object" form shall mean any form resulting from mechanical transformation or

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · LICENSE.txt (reported line 54)May include surrounding context.

text
permissions granted by this License.

"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation source, and
configuration files.

"Object" form shall mean any form resulting from mechanical transformation or

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · LICENSE.txt (reported line 147)May include surrounding context.

text
permissions granted by this License.

"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation source, and
configuration files.

"Object" form shall mean any form resulting from mechanical transformation or

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

This code file creates a temporary repository, writes multiple files with heredocs, initializes and commits a Git repository, and checks out branches. While comments describe what the script does for developers reading the file, there is no runtime disclosure, prompt, or other user-facing warning before these state-changing operations execute.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.