Back to skill

Security audit

GitHub PR Automation Pro

Security checks for vulnerabilities and agentic risk

Overview

This GitHub PR automation skill is purpose-related but unsafe because its scripts run shell commands with unvalidated user input while using an authenticated GitHub CLI session.

Install only if you are comfortable reviewing and fixing the scripts first. In particular, replace shell-string execSync calls with argument-array execution, validate PR numbers and branch/template/label inputs, and use least-privileged GitHub credentials. Treat the advertised auto-merge, approval, batch, and metrics features as unsupported by this artifact.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/create_pr.js:39
Finding
Shell Command Injection in Pull Request Creation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/create_pr.js:39-52` **Vulnerability Type**: OS command injection through unsafe shell command construction **Risk Level**: High ### Vulnerable Code ```javascript // Build gh pr create command let cmd = `gh pr create --title "${title}" --body "${prBody}"`; if (branch) { cmd += ` --head ${branch}`; } if (draft) { cmd += ' --draft'; } if (labels) { cmd += ` --label "${labels}"`; } console.log(`\n🚀 Creating PR: ${title}`); console.log(`Branch: ${branch || 'current'}\n`); try { const output = execSync(cmd, { encoding: 'utf8' }); ``` ### Technical Analysis The `title`, `body`, `branch`, and `labels` values originate from command-line arguments and are interpolated into a command string executed by `child_process.execSync`. The PR body may also contain template file contents. `execSync` executes string commands through a system shell. Adding double quotes around selected values does not safely neutralize shell metacharacters. An attacker can include closing quotes, command separators, command substitution expressions, redirections, or other shell syntax in a supplied value. The `branch` value is especially exposed because it is inserted without any quoting. Consequently, the shell may interpret attacker-controlled text as an additional local command instead of as a literal GitHub CLI argument. ### Attack Path 1. An attacker convinces a user or automation process to invoke `create_pr.js` with a crafted `--title`, `--body`, `--branch`, or `--labels` value. 2. The script places the malicious value directly into the `cmd` string. 3. `execSync(cmd)` passes the resulting string to the operating-system shell. 4. The shell parses the injected operators and executes the attacker's command. 5. The injected command runs with the same operating-system privileges, environment variables, filesystem access, and authenticated tooling available to the user running the Skill. ### Impact Assessment Su ...[truncated 760 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Avoid invoking the GitHub CLI through a shell command string. Use `execFileSync` or `spawnSync` with each argument supplied as a distinct array element: ```javascript const { execFileSync } = require('child_process'); const ghArgs = [ 'pr', 'create', '--title', title, '--body', prBody ]; if (branch) { ghArgs.push('--head', branch); } if (draft) { ghArgs.push('--draft'); } if (labels) { ghArgs.push('--label', labels); } const output = execFileSync('gh', ghArgs, { encoding: 'utf8', shell: false }); ``` Apply defense-in-depth controls as well: 1. Validate branch names against the expected Git reference syntax or resolve them through Git before use. 2. Validate labels using an explicit character and length policy. 3. Limit title and body lengths to reasonable values. 4. Validate template identifiers against a fixed allowlist such as `feature` and `bugfix`. 5. Do not attempt to implement custom shell escaping; argument-array execution is safer and less error-prone. 6. Run the Skill with the least-privileged GitHub token and operating-system account needed for PR creation. 7. Add automated tests containing quotes, semicolons, command substitutions, newlines, and shell redirection characters to verify that values remain literal arguments. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/monitor_pr.js:20
Finding
Shell Command Injection Through Pull Request Number<![CDATA[ ## Vulnerability Details **File Location**: `scripts/monitor_pr.js:20` **Vulnerability Type**: OS command injection through an unvalidated PR identifier **Risk Level**: High ### Vulnerable Code ```javascript const prData = execSync(`gh pr view ${prNumber} --json title,state,isDraft,mergeable,reviewDecision,statusCheckRollup`, { encoding: 'utf8' }); ``` The value is taken directly from the command line: ```javascript const args = process.argv.slice(2); const prIdx = args.indexOf('--pr'); if (prIdx === -1) { console.error('Usage: node monitor_pr.js --pr 123'); process.exit(1); } const prNumber = args[prIdx + 1]; monitorPR(prNumber); ``` ### Technical Analysis The value following `--pr` is accepted without checking that it is a numeric pull-request identifier. It is then interpolated, without quoting, into a string passed to `execSync`. Because string-based `execSync` uses a shell, shell operators contained in `prNumber` are interpreted as syntax. An attacker can append a command separator and an arbitrary command, then use shell comment syntax or otherwise construct the remainder so that the complete command remains valid. This is a direct command-injection vulnerability. Merely adding quotes would not provide reliable protection; shell invocation must be removed and the expected numeric format must be enforced. ### Attack Path 1. An attacker supplies or causes automation to supply a crafted value after the `--pr` option. 2. The argument parser assigns that value to `prNumber` without validation. 3. `monitorPR` inserts it into the `gh pr view` shell command. 4. `execSync` invokes the system shell with the constructed command. 5. The shell executes the injected command with the privileges of the user running the monitor. A normal PR number is expected to contain only decimal digits, so no shell metacharacters are necessary for legitimate operation. ### Impact Assessment Successful exploitation permits arbitrary local command execution ...[truncated 582 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Validate the PR identifier and execute `gh` without a shell: ```javascript const { execFileSync } = require('child_process'); if (!/^\d+$/.test(prNumber)) { console.error('Invalid PR number: expected a positive integer'); process.exit(1); } const prData = execFileSync( 'gh', [ 'pr', 'view', prNumber, '--json', 'title,state,isDraft,mergeable,reviewDecision,statusCheckRollup' ], { encoding: 'utf8', shell: false } ); ``` Additional hardening measures should include: 1. Reject a missing value after `--pr` explicitly. 2. Parse the identifier as a safe positive integer and enforce a reasonable upper bound. 3. Use `execFileSync` or `spawnSync` with an argument array for every external command. 4. Keep `shell: false` explicit where supported. 5. Run monitoring with a read-only or otherwise least-privileged GitHub token. 6. Add regression tests using semicolons, quotes, whitespace, command substitutions, and redirection characters to ensure malformed identifiers are rejected before process execution. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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 (7)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The code only covers a narrow subset of the declared functionality: PR creation with optional template usage and simple labeling automation. It does not implement review, approval, merging, monitoring of PR or CI status, batch processing, or metrics collection. The description significantly overstates the implemented behavior, so the declared purpose does not accurately represent what this code chunk actually does.

Ae1

High
Category
analysis-evasion
Content
node scripts/monitor_pr.js --pr 123
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill advertises and demonstrates network-capable GitHub operations via the `gh` CLI and Node scripts, but it does not declare any explicit tool scope, permissions, or allowed-tools boundary. That makes the skill harder to constrain at runtime and increases the chance of unintended repository access or outbound actions beyond what a user expects.

Vague Triggers

Medium
Confidence
88% confidence
Finding
The invocation guidance is very broad and could cause the skill to be selected for many common PR-related requests, including ones involving sensitive repository modifications. Over-broad routing increases the likelihood that powerful automation is invoked when a narrower, safer skill or manual review would be more appropriate.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill promotes auto-merge and approval automation without any warning, gating, or human confirmation language, even though these actions can directly change repository state and ship code. In a GitHub automation context, silent approval or merge workflows can bypass review intent, merge unsafe changes, or amplify mistakes across many PRs.

Context-Inappropriate Capability

Medium
Confidence
86% confidence
Finding
The manifest describes GitHub pull request workflow automation, which reasonably implies interacting with GitHub APIs or tooling, but this implementation does so by spawning local shell commands through child_process.execSync. That adds local command-execution capability, including dependence on the host shell environment, beyond what is semantically necessary for PR management itself.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The script interpolates the user-controlled `prNumber` directly into a shell command passed to `execSync`, which invokes a shell. An attacker can supply shell metacharacters such as `;`, `&&`, or command substitution to execute arbitrary commands on the host running the script, not just query a PR.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/create_pr.js:17

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/monitor_pr.js:12