Back to skill

Security audit

PR Review Loop

Security checks for vulnerabilities and agentic risk

Overview

This skill is a PR review automation helper, but it can drive merges and branch deletion even when the stated review score gate has not been met.

Review before installing. Use this only in tightly scoped trusted repositories with branch protection, least-privileged GitHub tokens, and explicit human approval before any merge or branch deletion. Remove or disable force_merge behavior and Telegram escalation unless they are deliberately configured and audited.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/pr-review-loop.sh:63
Finding

Automatic Force-Merge Bypasses the Required Review Score

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/pr-review-loop.sh:39
Finding

Untrusted Repository Identifiers Are Interpolated into jq Programs

Content
View full analysis
&2; exit 1; } jq ".\"${KEY}\" = {rounds: ${ROUNDS}, maxRounds: 5, lastScore: $([ -n "$SCORE" ] && echo "$SCORE" || echo "null"), sameScoreCount: ${SAME_COUNT}}" \ "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE" ) 200>"$LOCK" ``` `KEY` is derived directly from caller-provided arguments: ```bash REPO="${1:?Usage: pr-review-loop.sh }" PR="${2:?Usage: pr-review-loop.sh }" KEY="${REPO}#${PR}" ``` ### Technical Analysis The script embeds `KEY` directly into jq source code. Shell quoting prevents shell expansion of jq metacharacters, but it does not make the value safe for inclusion in a jq string literal. A value containing a double quote, backslash, or jq syntax can terminate or modify the generated jq expression. This can change which state entry is read or written, transform the state document unexpectedly, or make the jq operation fail. Because state fields influence `ROUNDS`, `SAME_COUNT`, and the eventual merge action, state manipulation can affect the review decision. Exploitation through the normal GitHub workflow has an important precondition: the crafted identifier must reach this code after the preceding `gh api` call returns a Greptile review. Invalid GitHub repository identifiers will ordinarily cause an earlier `no_review` result. The unsafe construction nevertheless remains exploitable in environments that accept attacker-controlled identifiers through a proxy, mocked API, wrapper, or other caller-cont ...[truncated 1199 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/pr-review-loop.sh:10
Finding

Caller-Controlled State Path and Predictable Temporary File Enable File Clobbering

Content
View full analysis
}" PR="${2:?Usage: pr-review-loop.sh }" STATE_FILE="${3:-review-state.json}" # Initialize state file if missing if [ ! -f "$STATE_FILE" ]; then echo '{}' > "$STATE_FILE" fi ``` ```bash # Update state (use lockfile to prevent concurrent write races) LOCK="${STATE_FILE}.lock" ( flock -w 5 200 || { echo '{"error":"Could not acquire state lock"}' >&2; exit 1; } jq ".\"${KEY}\" = {rounds: ${ROUNDS}, maxRounds: 5, lastScore: $([ -n "$SCORE" ] && echo "$SCORE" || echo "null"), sameScoreCount: ${SAME_COUNT}}" \ "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE" ) 200>"$LOCK" ``` ### Technical Analysis The optional third argument is accepted as an unrestricted output path. If the path does not identify a regular file, the initialization redirection can create or truncate a file accessible to the executing account. The update also writes to the predictable path `${STATE_FILE}.tmp`. A local attacker who can write in the state directory can pre-create that path as a symbolic link to another file. Shell redirection follows symbolic links, allowing jq output to overwrite the link target before `mv` runs. The lock only coordinates processes that voluntarily use the same lock file. It does not prevent another local process from creating or replacing the state file, lock file, or temporary path, and the initial state read occurs outside the lock. ### Attack Path 1. The attacker either controls the third script argument or has write access to the directory containing the selected state file. 2. For direct clobbering, the attacker supplies a path to a file that the executing agent can overwrite and that is absent ...[truncated 1056 chars]
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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 (9)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The declared description presents an end-to-end autonomous PR review loop, but the supplied code chunk is only a review-fetching and decision-output helper. Its real behavior is limited to reading Greptile reviews/comments via GitHub API, extracting a score, maintaining loop state, and suggesting an action in JSON. While this supports a broader PR-review workflow, it does not itself carry out the key declared actions: fixing issues, committing/pushing updates, retriggering review, or merging. It also does not implement webhook or polling triggers. The code's primary purpose is narrower than the declared purpose, so this is a material description-behavior mismatch.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill performs destructive operations, including merging a PR and deleting its branch, without prominent warnings or guardrails. In this context, omission is dangerous because an autonomous agent may execute irreversible repository changes without adequate operator awareness, confirmation, or policy checks.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documentation says to merge anyway after max rounds or repeated unchanged scores, directly bypassing the stated quality gate of score >= 4/5. In context, this is dangerous because it can force merges of inadequately reviewed or still-defective code, undermining review controls and potentially shipping vulnerable changes.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script does more than fetch and parse review data: it decides whether to merge, including a 'force_merge' outcome after 5 rounds or 2 repeated scores, regardless of whether review issues remain unresolved. In the context of an autonomous PR-review skill, this creates a real integrity risk because downstream agents may treat this output as authorization to merge code that has not actually met policy or human approval requirements.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest description says the skill should trigger on commands like "review my PR", which is broad natural language that could overlap with ordinary conversation rather than a tightly scoped command. The file does provide one specific trigger format, but it does not clearly constrain or exclude broader phrasings, increasing the risk of unintended invocation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill directs the agent to repeatedly modify code, commit, and push to remote branches without clearly warning about the scope and persistence of those changes. This increases the chance of unintended code alterations, privilege misuse, or noisy automated churn, especially when review comments are ambiguous or manipulated.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill introduces an external notification path to a 'Master on Telegram' that is unrelated to core PR review mechanics and can cause unauthorized data egress. PR metadata, code review content, branch names, or repository details could be sent to an out-of-band channel without clear authorization or data handling controls.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The header comments describe the script as fetch/parse/output only, but the implementation persists state and makes autonomous merge-policy decisions. This mismatch is dangerous because reviewers, operators, or calling agents may grant it broader trust than intended and unknowingly enable risky auto-merge behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

This shell script calls gh api to retrieve pull request reviews and inline comments, then includes the review body and comments in its JSON output. The file contains no user-facing warning, prompt, or explanatory comment disclosing that remote PR metadata and comment text will be fetched and surfaced for downstream agent processing.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.