Back to skill

Security audit

pinterest-research

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed Pinterest research helper, but it needs review because its script can send broader authenticated Crawlora requests than the documented read-only Pinterest lookups.

Review before installing if you will provide a real Crawlora API key. The intended behavior is public Pinterest lookup through Crawlora, but the helper should ideally be tightened to GET-only documented routes with segment-aware path validation before use with a valuable or paid API key.

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

Warning
Location
scripts/crawlora.sh:42
Finding
Overbroad Route and HTTP Method Allowlist Permits Undocumented Authenticated Requests<![CDATA[ ## Vulnerability Details **File Location**: `scripts/crawlora.sh:42-75` **Vulnerability Type**: Insufficient route and HTTP method validation **Risk Level**: Medium ### Vulnerable Code ```bash # This skill's helper is limited to its documented Crawlora route set. Keep # caller-account surfaces and unrelated API routes out of the helper even if # someone supplies an undocumented path directly. case "$method" in GET|POST) ;; *) echo "only GET and POST are supported by the pinterest-research skill" >&2 exit 2 ;; esac # Reject path syntax that could smuggle a route through a shell glob check. case "$path" in ""|*[?#%]*|*..*|*//* ) echo "invalid path for the pinterest-research skill" >&2 exit 2 ;; esac case "$path" in /pinterest/board/*/*) ;; /pinterest/categories) ;; /pinterest/ideas/*) ;; /pinterest/pin/*) ;; /pinterest/search) ;; /pinterest/user/*) ;; /pinterest/user/*/boards) ;; /pinterest/user/*/pins) ;; *) echo "path is not in the pinterest-research skill catalog" >&2 exit 2 ;; esac ``` ### Technical Analysis The endpoint reference defines all eight supported Pinterest operations as `GET` requests. However, the script accepts both `GET` and `POST` for every path admitted by its route allowlist. This permits authenticated POST requests even though no documented endpoint requires that method. The path allowlist uses shell `case` glob patterns. In Bash patterns, `*` can match slash characters, unlike a segment-aware URL router. Consequently: - `/pinterest/user/*` can match arbitrary nested paths below `/pinterest/user/`. - `/pinterest/pin/*` and `/pinterest/ideas/*` can accept values containing additional path segments. - `/pinterest/board/*/*` does not strictly enforce exactly two nonempty path parameters. - The more specific user board and pin patterns do not meaningfully constrain routing because the earlier `/pinterest/user/*` pattern already accepts those paths and other nested rout ...[truncated 2108 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove POST support because every documented endpoint is GET-only: ```bash if [ "$method" != "GET" ]; then echo "only GET is supported by the pinterest-research skill" >&2 exit 2 fi ``` 2. Replace broad shell globs with segment-aware validation. Ensure each parameter is nonempty and cannot contain `/`, query delimiters, fragments, percent encoding, or traversal sequences. 3. Explicitly distinguish the three supported user route forms instead of relying on `/pinterest/user/*`: ```bash segment='[A-Za-z0-9._-]+' if [[ "$path" =~ ^/pinterest/categories$ ]] || [[ "$path" =~ ^/pinterest/search$ ]] || [[ "$path" =~ ^/pinterest/pin/${segment}$ ]] || [[ "$path" =~ ^/pinterest/ideas/${segment}$ ]] || [[ "$path" =~ ^/pinterest/board/${segment}/${segment}$ ]] || [[ "$path" =~ ^/pinterest/user/${segment}$ ]] || [[ "$path" =~ ^/pinterest/user/${segment}/boards$ ]] || [[ "$path" =~ ^/pinterest/user/${segment}/pins$ ]]; then : else echo "path is not in the pinterest-research skill catalog" >&2 exit 2 fi ``` 4. If valid Pinterest identifiers require a broader character set, define and document that set explicitly rather than allowing arbitrary path content. 5. Add negative tests covering extra path segments, empty parameters, unsupported methods, encoded delimiters, duplicate slashes, and undocumented nested routes. 6. Maintain a method-to-route mapping if POST endpoints are added later, allowing POST only for the exact endpoints that require it. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (9)

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill invokes a shell helper (`scripts/crawlora.sh`) but does not declare any `permissions` or `allowed-tools` scope. This creates an authorization gap where an agent may execute shell-capable actions without an explicit tool boundary, increasing the risk of unintended command execution or broader-than-necessary runtime access.

External Transmission

Medium
Category
Data Exfiltration
Content
#!/usr/bin/env bash
# Crawlora REST helper — minimal, dependency-free (curl only).
# Calls https://api.crawlora.net/api/v1 with your Crawlora API key.
# Get a free key (2,000 credits/mo, no card) at https://crawlora.net?utm_source=github&utm_medium=referral&utm_campaign=crawlora-skills.
#
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
#!/usr/bin/env bash
# Crawlora REST helper — minimal, dependency-free (curl only).
# Calls https://api.crawlora.net/api/v1 with your Crawlora API key.
# Get a free key (2,000 credits/mo, no card) at https://crawlora.net?utm_source=github&utm_medium=referral&utm_campaign=crawlora-skills.
#
# Usage:
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
#!/usr/bin/env bash
# Crawlora REST helper — minimal, dependency-free (curl only).
# Calls https://api.crawlora.net/api/v1 with your Crawlora API key.
# Get a free key (2,000 credits/mo, no card) at https://crawlora.net?utm_source=github&utm_medium=referral&utm_campaign=crawlora-skills.
#
# Usage:
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
#!/usr/bin/env bash
# Crawlora REST helper — minimal, dependency-free (curl only).
# Calls https://api.crawlora.net/api/v1 with your Crawlora API key.
# Get a free key (2,000 credits/mo, no card) at https://crawlora.net?utm_source=github&utm_medium=referral&utm_campaign=crawlora-skills.
#
# Usage:
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
#!/usr/bin/env bash
# Crawlora REST helper — minimal, dependency-free (curl only).
# Calls https://api.crawlora.net/api/v1 with your Crawlora API key.
# Get a free key (2,000 credits/mo, no card) at https://crawlora.net?utm_source=github&utm_medium=referral&utm_campaign=crawlora-skills.
#
# Usage:
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
# Keep the API key out of the curl process command line. A private temporary
# config supplies the header and is removed automatically on exit.
curl_config="$(mktemp "${TMPDIR:-/tmp}/crawlora-curl.XXXXXX")"
chmod 600 "$curl_config"
trap 'rm -f "$curl_config"' EXIT
printf 'header = "x-api-key: %s"\n' "$CRAWLORA_API_KEY" >"$curl_config"
auth=(--config "$curl_config")
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

External Transmission

Medium
Category
Data Exfiltration
Content
[ -n "$body" ] || body='{}'
  # Stream the body on stdin so curl never interprets a user value as its
  # @file shorthand (and cannot read local files supplied in a request body).
  printf '%s' "$body" | curl -fsS -X "$method" "${auth[@]}" \
    -H "Content-Type: application/json" --data-binary @- "${base}${path}"
fi
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Low
Confidence
89% confidence
Finding
This markdown file explicitly instructs callers to send requests to an external API and include `x-api-key: $CRAWLORA_API_KEY`. Because markdown files should warn about behaviors that could affect privacy or system integrity, the absence of any caution about transmitting requests with credentials is a missing user warning.

Static analysis

No suspicious patterns detected.