Back to skill

Security audit

pr-reviewer

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its PR-review purpose, but its review script has a serious unsafe-code path where a crafted pull-request filename can run local Python code during review.

Review this skill carefully before installing or running it on untrusted pull requests. Use a low-privilege GitHub account or token, avoid running it in an environment with unrelated secrets, and do not enable cron or automated review until the filename-to-Python injection issue is fixed by passing PR file data through stdin, argv, or JSON rather than embedding it in source code.

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/pr-review.sh:259
Finding

Arbitrary Python Code Execution Through Attacker-Controlled PR Filenames

Content
View full analysis
/dev/null || echo "" } ``` ```bash check_test_coverage() { python3 -c " import sys files = '''$1'''.strip().split('\n') src, tests = [], [] for f in files: f = f.strip() if not f: continue if f.endswith('_test.go') or 'test_' in f.split('/')[-1] or f.endswith('_test.py') or f.endswith('.test.ts') or f.endswith('.test.js') or f.endswith('.spec.ts') or f.endswith('.spec.js'): tests.append(f) elif f.endswith(('.go', '.py', '.ts', '.tsx', '.js', '.jsx')): src.append(f) missing = [] for s in src: has_test = False s_dir = '/'.join(s.split('/')[:-1]) s_name = s.split('/')[-1].rsplit('.', 1)[0] for t in tests: t_dir = '/'.join(t.split('/')[:-1]) if t_dir == s_dir or f'test_{s_name}' in t or f'{s_name}_test' in t or f'{s_name}.test' in t or f'{s_name}.spec' in t: has_test = True break skip = any(k in s for k in ['__init__', 'main.go', 'main.py', 'config', 'types', 'models', 'schema', 'index.ts', 'index.js']) if not has_test and not skip: missing.append(s) if missing: print('Files without corresponding test changes:') for f in missing: print(f' - {f}') else: print('Test coverage looks adequate for changed files.') " } ``` The data flow into the vulnerable function is: ```bash files=$(get_pr_files "$pr_num") test_coverage=$(check_test_coverage "$files") ``` ### Technical Analysis GitHub pull-request contributors control the names of files included in their commits. `get_pr_files` retrieves those names and stores them i ...[truncated 2967 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises and documents file-writing behavior via PR_REVIEW_STATE and PR_REVIEW_OUTDIR, but it does not declare an explicit tool scope such as permissions or allowed-tools. That mismatch can cause users or orchestrators to underestimate the skill’s ability to modify local state, which is a real security and safety issue even if the writes are expected for normal operation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The skill supports posting GitHub review comments using an authenticated gh session, which is a user-affecting write action against a remote service, but this capability is only briefly mentioned in prerequisites and quick-start examples. Under-disclosing remote write behavior increases the risk of unintended comments being posted to repositories, especially in automated or cron-driven use.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The script creates the reviews directory and initializes a persistent state file, and later writes review reports to files under that directory. Although this behavior is visible in code comments, there is no runtime confirmation or user-facing disclosure when the file write occurs, which can surprise users if they do not expect local artifacts to be created.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The script sends the generated report file to GitHub using gh pr comment --body-file, which transmits locally generated content to an external service. While the command name implies posting, there is no explicit disclosure of what data is being uploaded at the moment of transmission beyond a success log afterward.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/pr-review.sh:168