Back to skill

Security audit

Propel Code Review Smoke

Security checks for vulnerabilities and agentic risk

Overview

The skill performs a coherent code-review integration, but it handles API credentials and source diffs in ways users should review carefully before installing.

Install only if you are comfortable uploading reviewed diffs to Propel and granting a reviews:read/reviews:write token. Prefer setting PROPEL_API_KEY outside chat for the current session or a proper secret store, avoid saving it in shell profiles, do not run with untrusted PROPEL_API_BASE_URL/PROPEL_API_URL values, and replace the documented fixed /tmp diff path with a private mktemp file that is removed after use.

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

Error
Location
scripts/create_review.sh:36
Finding

Unvalidated API Endpoint Override Exposes Bearer Tokens and Source Code

Content
View full analysis
"$CURL_CONFIG_FILE" printf 'header = "Content-Type: application/json"\n' >>"$CURL_CONFIG_FILE" HTTP_CODE="" for ((attempt = 1; attempt <= MAX_ATTEMPTS; attempt++)); do if ! HTTP_CODE="$( jq -n \ --rawfile diff "$DIFF_FILE" \ --arg repo "$REPO_SLUG" \ --arg base "$BASE_COMMIT" \ --arg head "$HEAD_COMMIT_SHA" \ --arg branch "$BRANCH_NAME" \ '({diff:$diff, repository:$repo, base_commit:$base} + (if $head != "" then {head_commit_sha:$head} else {} end) + (if $branch != "" then {branch:$branch} else {} end))' \ | curl -sS -o "$BODY_FILE" -w "%{http_code}" \ --config "$CURL_CONFIG_FILE" \ --data-binary @- \ "$API_URL/v1/reviews" )"; then ``` The polling and feedback scripts use the same endpoint-override pattern and attach the same credential: ```bash API_URL="${PROPEL_API_BASE_URL:-${PROPEL_API_URL:-https://api.propelcode.ai}}" ``` ```bash printf 'header = "Authorization: Bearer %s"\n' "$PROPEL_API_KEY ...[truncated 2493 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:42
Finding

API Token Is Collected Through Chat and Persisted in Plaintext Shell Profiles

Content
View full analysis
`PROPEL_API_KEY` is not set. Opening the token creation page: > https://app.propelcode.ai/administration/settings?tab=review-api-tokens&token_name=Claude+Code&scopes=reviews:read,reviews:write > The name and scopes are pre-filled. Click **Create token**, copy it, and paste it here. ``` It then validates only a prefix: ```text Step 2 — Wait for the user to paste the token. Do not proceed until the user pastes a value starting with `rev_`. If the value doesn't start with `rev_`, tell them it doesn't look valid and ask them to try again. ``` Finally, it instructs the agent to interpolate and persist that value in a shell startup file: ```bash case "$SHELL" in */zsh) SHELL_RC="$HOME/.zshrc" ;; */bash) SHELL_RC="$HOME/.bashrc" ;; *) SHELL_RC="" ;; esac; if [ -z "$SHELL_RC" ] && [ -f "$HOME/.zshrc" ]; then SHELL_RC="$HOME/.zshrc"; fi; if [ -z "$SHELL_RC" ] && [ -f "$HOME/.bashrc" ]; then SHELL_RC="$HOME/.bashrc"; fi; if [ -n "$SHELL_RC" ]; then printf '\n# Propel Review API token\nexport PROPEL_API_KEY="%s"\n' "" >> "$SHELL_RC" && echo "Saved to $SHELL_RC"; else echo "No shell profile found"; fi; export PROPEL_API_KEY="" ``` ### Technical Analysis Conversation channels are not appropriate secret-entry mechanisms. A token pasted into chat may be retained in conversation history, audit logs, telemetry, screenshots, exports, or other systems involved in processing agent messages. The persistence instruction writes the token in plaintext to `.zshrc` or `.bashrc`. These files are long-lived, commonly backed up, and may be read by unrelated local processes operating under the same account. Every future interactive shell also i ...[truncated 2183 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:228
Finding

Predictable Shared Temporary Diff Path Enables Symlink Overwrite and Source Disclosure

Content
View full analysis
/tmp/review_api.diff ``` The same fixed path is used in the complete production example: ```bash BASE_BRANCH=$(gh pr view --json baseRefName -q '.baseRefName' 2>/dev/null || git remote show origin | sed -n '/HEAD branch/s/.*: //p') BASE_COMMIT=$(git rev-parse "$BASE_BRANCH") HEAD_COMMIT=$(git rev-parse HEAD) BRANCH=$(git rev-parse --abbrev-ref HEAD) REPO_SLUG=$(git remote get-url origin | sed -E 's#(git@github.com:|https://github.com/)##; s/\.git$//') git diff "$BASE_BRANCH" > /tmp/review_api.diff CREATE_RESPONSE=$( scripts/create_review.sh \ --diff-file /tmp/review_api.diff \ --repo "$REPO_SLUG" \ --base-commit "$BASE_COMMIT" \ --head-commit-sha "$HEAD_COMMIT" \ --branch "$BRANCH" ) ``` ### Technical Analysis `/tmp` is generally shared among local users. The fixed filename `/tmp/review_api.diff` can be predicted and pre-created. Standard shell redirection follows symbolic links, so if the path is a symlink, the command opens and truncates the symlink target using the invoking user's permissions. The resulting file's permissions depend on the user's umask. The documented workflow neither creates it atomically with restrictive permissions nor removes it afterward. The file can therefore retain proprietary source changes after review submission. The scripts themselves generally use `mktemp`; the weakness is in the documented and recommended invocation workflow. ### Attack Path #### Symlink overwrite 1. A local attacker predicts that the user will run the documented workflow. 2. The attacker creates `/tmp/review_api.diff` as a symbolic link to a file writable by the victim. 3. The victim executes: ```bash ...[truncated 1195 chars]
Remediation
View remediation
"$DIFF_FILE" ``` 2. Pass `"$DIFF_FILE"` to `create_review.sh` rather than `/tmp/review_api.diff`. 3. Delete the file immediately after successful submission if it is no longer needed. 4. Set a restrictive umask before creating any file containing source code: ```bash umask 077 ``` 5. Avoid reusable or predictable temporary filenames in all examples and recommended workflows. 6. Consider piping the diff directly into a helper designed to consume standard input, eliminating the intermediate file when practical. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code chunk is limited to review creation via POST to /v1/reviews using a diff file, repository slug, and base commit, then returning the API response containing a review_id. It includes argument parsing, validation, retries, and error handling, which are supporting details and consistent with submission. However, the declared description claims a broader workflow: asynchronous reviews plus polling, findings retrieval, and comment feedback. None of those later-stage capabilities appear in this code. Therefore the description overstates what this supplied code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a broader end-to-end capability: running async diff-based code reviews with Propel, polling for completion, retrieving findings, and sending feedback comments. The supplied code chunk is much narrower. It accepts a review ID, authenticates with PROPEL_API_KEY, repeatedly GETs /v1/reviews/, respects poll timing hints, handles retries/timeouts, and emits the final JSON when status becomes completed or failed. This aligns with only the polling portion of the description. There is no code to generate or submit diffs, start a review job, parse findings into comments, or post feedback. Because the actual behavior is a subset of the declared purpose and omits key stated capabilities, the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a full review workflow skill: submit diffs for async review, poll until complete, fetch structured findings, and send comment feedback. The supplied code chunk instead is a standalone smoke-test script focused on permission behavior of the /v1/reviews endpoint. It creates three test cases using valid/invalid repo and token combinations and checks for expected status codes. While it does submit a diff to the review endpoint, that is only in service of permission testing, not actual review orchestration. Key declared behaviors—polling, result retrieval, and comment feedback—are absent, and the code's primary purpose is materially different from the description.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill instructs the agent to append the API token to the user's shell profile, creating long-lived credential persistence on disk. This materially increases exposure because shell startup files are broadly accessible to local tools, may be backed up or synced, and can unintentionally leak secrets through logs, history, or later automation.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 197)May include surrounding context.

md
- `scripts/poll_review.sh` wraps polling `GET /v1/reviews/:review_id` until

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 208)May include surrounding context.

md
- `scripts/poll_review.sh` wraps polling `GET /v1/reviews/:review_id` until

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 236)May include surrounding context.

md
- `scripts/poll_review.sh` wraps polling `GET /v1/reviews/:review_id` until

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 272)May include surrounding context.

md
- `scripts/poll_review.sh` wraps polling `GET /v1/reviews/:review_id` until

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 321)May include surrounding context.

md
- `scripts/poll_review.sh` wraps polling `GET /v1/reviews/:review_id` until

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill clearly instructs use of shell commands, browser launching, git, and helper scripts, but it does not declare any explicit tool scope or allowed-tools boundary. That increases the chance an agent executes broader local commands than intended, especially because the workflow includes filesystem writes and networked API interactions.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill directs the agent to open a browser to a credential-generation page and guide the user through obtaining a token. That expands the skill from code review into credential acquisition, which is sensitive behavior and can normalize phishing-like flows or unnecessary secret handling by the agent.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
88% confidence
Finding

The workflow explicitly asks the user to create a token with write scope and paste it into the session, then later persists it. This is a session-persistence and credential-handling risk because it encourages collecting a privileged secret into agent-visible context and potentially retaining it beyond the immediate operation.

Content

Scanner excerpt · SKILL.md (reported line 46)May include surrounding context.

md
Message to user:
> `PROPEL_API_KEY` is not set. Opening the token creation page:
> https://app.propelcode.ai/administration/settings?tab=review-api-tokens&token_name=Claude+Code&scopes=reviews:read,reviews:write
> The name and scopes are pre-filled. Click **Create token**, copy it, and paste it here.

Bash command:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The instruction to modify ~/.bashrc or ~/.zshrc to store an API key is given without any warning about the security and system-modification implications. Users may unknowingly authorize persistent credential storage and shell configuration changes that outlive the immediate task.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code reads the entire diff file and sends it in a JSON request body to an external API endpoint. Although the script usage documents the API key and URL, it does not provide a clear warning that local code changes may be uploaded off-host, which is a privacy- and data-handling-relevant operation.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/create_review.sh (reported line 145)May include surrounding context.

sh
'({diff:$diff, repository:$repo, base_commit:$base}
        + (if $head != "" then {head_commit_sha:$head} else {} end)
        + (if $branch != "" then {branch:$branch} else {} end))' \
      | curl -sS -o "$BODY_FILE" -w "%{http_code}" \
        --config "$CURL_CONFIG_FILE" \
        --data-binary @- \
        "$API_URL/v1/reviews"

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/create_review.sh (reported line 128)May include surrounding context.

sh
BODY_FILE="$(mktemp)"
CURL_CONFIG_FILE="$(mktemp)"
chmod 600 "$CURL_CONFIG_FILE"
trap 'rm -f "$BODY_FILE" "$CURL_CONFIG_FILE"' EXIT
printf 'header = "Authorization: Bearer %s"\n' "$PROPEL_API_KEY" >"$CURL_CONFIG_FILE"
printf 'header = "Content-Type: application/json"\n' >>"$CURL_CONFIG_FILE"

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/poll_review.sh (reported line 152)May include surrounding context.

sh
BODY_FILE="$(mktemp)"
CURL_CONFIG_FILE="$(mktemp)"
chmod 600 "$CURL_CONFIG_FILE"
trap 'rm -f "$BODY_FILE" "$CURL_CONFIG_FILE"' EXIT
printf 'header = "Authorization: Bearer %s"\n' "$PROPEL_API_KEY" >"$CURL_CONFIG_FILE"
printf 'header = "Content-Type: application/json"\n' >>"$CURL_CONFIG_FILE"

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/post_comment_feedback.sh (reported line 118)May include surrounding context.

sh
BODY_FILE="$(mktemp)"
CURL_CONFIG_FILE="$(mktemp)"
chmod 600 "$CURL_CONFIG_FILE"
trap 'rm -f "$BODY_FILE" "$CURL_CONFIG_FILE"' EXIT
printf 'header = "Authorization: Bearer %s"\n' "$PROPEL_API_KEY" >"$CURL_CONFIG_FILE"
printf 'header = "Content-Type: application/json"\n' >>"$CURL_CONFIG_FILE"

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/post_comment_feedback.sh (reported line 124)May include surrounding context.

sh
printf 'header = "Content-Type: application/json"\n' >>"$CURL_CONFIG_FILE"

if ! HTTP_CODE="$(
  curl -sS -o "$BODY_FILE" -w "%{http_code}" \
    --config "$CURL_CONFIG_FILE" \
    -X POST "$API_URL/v1/reviews/$REVIEW_ID/comments/feedback" \
    --data-binary "$PAYLOAD"

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/smoke_test_permissions.sh (reported line 142)May include surrounding context.

sh
if ! code="$(
    jq -n --rawfile diff "$DIFF_FILE" --arg repo "$repo" --arg base "$BASE_COMMIT" \
      '{diff:$diff, repository:$repo, base_commit:$base}' \
      | curl -sS -o "$body_file" -w "%{http_code}" \
        -H "Authorization: Bearer $token" \
        -H "Content-Type: application/json" \
        --data-binary @- \

Static analysis

No suspicious patterns detected.