Back to skill

Security audit

Greptile

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate Greptile API wrapper, but it has a real command-injection flaw and uses high-impact repository tokens with limited safeguards.

Review carefully before installing. Only use this with repositories you are allowed to share with Greptile, prefer a fine-grained token dedicated to this integration, and fix or avoid the status command until the Python string construction is replaced with safe argument passing.

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/greptile.sh:92
Finding

Arbitrary Python Code Execution via Unsanitized Repository Parameters

Content
View full analysis

Vulnerability Details

File Location: scripts/greptile.sh, line 92
Vulnerability Type: Command injection through dynamically constructed Python source
Risk Level: High

Vulnerable Code

bash
REPO_ID=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${REMOTE}:${BRANCH}:${REPO}', safe=''))")

Technical Analysis

The status command interpolates the user-controlled REMOTE, BRANCH, and REPO variables directly into source code supplied to python3 -c.

Because these values are placed inside a single-quoted Python string without escaping, an input containing a single quote can terminate the string and append arbitrary Python statements. Shell quoting does not prevent this vulnerability: after shell expansion, the resulting text is passed to Python as executable source code.

The affected values originate from command-line arguments:

  • REPO is the required repository argument.
  • BRANCH is an optional positional argument.
  • REMOTE can be supplied through --remote.

For example, a crafted branch can use the following injection structure:

text
x',safe=''));__import__('os').system('id');#

When incorporated into the python3 -c expression, the payload closes the intended function call, invokes os.system, and comments out the remaining source.

Attack Path

  1. An attacker causes the skill to invoke its status command with a crafted repository, branch, or --remote value.
  2. parse_repo_branch or parse_flags stores the malicious input without validation.
  3. Line 92 concatenates that input directly into Python source code.
  4. python3 -c parses and executes the injected Python statements.
  5. The injected code can launch arbitrary operating-system commands with the privileges of the user running the skill.
  6. Those commands can access local files and environment variables available to the process, including Greptile and repository-access credentials.

A representative invocation structure is:

`` ...[truncated 838 chars]

Remediation
View remediation

Remediation Suggestions

Do not embed command-line data in Python source. Pass the value as a positional argument:

bash
REPO_ID=$(python3 -c \
  'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' \
  "${REMOTE}:${BRANCH}:${REPO}")

Apply additional defense-in-depth measures:

  1. Restrict REMOTE to the explicitly supported values:

    bash
    case "$REMOTE" in
      github|gitlab) ;;
      *)
        echo "Error: --remote must be github or gitlab" >&2
        exit 1
        ;;
    esac
    
  2. Validate repository identifiers against the syntax accepted by the target API.

  3. Reject control characters, including newlines and null-like input, in repository and branch values.

  4. Make parse_flags fail on unsupported flags and on --remote without a following value instead of silently ignoring malformed input.

  5. Add regression tests containing single quotes, double quotes, semicolons, newlines, command substitutions, and Python syntax in every user-controlled field.

  6. Run the skill with least-privilege API tokens and operating-system permissions to reduce the consequences of future input-handling defects.

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 invokes shell and network-capable tooling (curl, jq, gh, and a shell script wrapper) but does not declare any explicit tool scope such as permissions or allowed-tools. In an agent environment, that omission can let the skill run with broader-than-necessary capabilities, increasing the chance of unintended external requests, token use, or shell-side effects when the skill is invoked.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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/greptile.sh (reported line 13)May include surrounding context.

sh
set -eo pipefail

API="https://api.greptile.com/v2"
TOKEN="${GREPTILE_TOKEN:?Set GREPTILE_TOKEN}"
GH_TOKEN="${GREPTILE_GITHUB_TOKEN:-${GITHUB_TOKEN:-}}"

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

The index operation performs a POST to an external service and includes both a Greptile bearer token and a GitHub token in headers, enabling third-party access to repository contents for indexing. In this skill's context, that is security-relevant because running it against private repositories can expose proprietary source code and credential-scoped repository access outside the local trust boundary.

Content

Scanner excerpt · scripts/greptile.sh (reported line 67)May include surrounding context.

sh
index)
    parse_repo_branch "$@"
    parse_flags "${REMAINING_ARGS[@]}"
    curl -sf -X POST "$API/repositories" \
      -H "Authorization: Bearer $TOKEN" \
      -H "X-GitHub-Token: $GH_TOKEN" \
      -H "Content-Type: application/json" \

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script sends repository identifiers, branch names, and in other modes user-supplied questions/searches to Greptile's external API, but provides no explicit warning, consent step, or visibility at the point of transmission. In an agent-skill context, this is meaningful because users may assume the tool operates locally while it actually exports potentially sensitive codebase context and prompts to a third party using both Greptile and GitHub credentials.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.