Back to skill

Security audit

claw-pet

Security checks for vulnerabilities and agentic risk

Overview

The skill is openly designed to call a pet-catching backend, but it can send an API key to any configured URL without enforcing HTTPS and has broad trigger wording that could cause unintended authenticated calls.

Review before installing. Only configure this skill with a backend you control, use an HTTPS URL, avoid putting production secrets in _meta.json, and prefer a narrowly scoped API key that can only perform the catch action. Be aware that casual catch/fish phrasing may trigger a real authenticated request.

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/catch_pet.py:25
Finding
Bearer Credential Can Be Transmitted Without Enforced HTTPS## Vulnerability Details **File Location**: `scripts/catch_pet.py`, lines 25–26 and 36–48 **Vulnerability Type**: Sensitive credential transmission without transport-security validation **Risk Level**: Medium ### Vulnerable Code ```python config = { "CATCH_API_URL": os.environ.get("CATCH_API_URL") or meta.get("CATCH_API_URL") or "", "API_KEY": os.environ.get("API_KEY") or meta.get("API_KEY") or "", } ``` ```python def build_request(url: str, api_key: str) -> urllib.request.Request: payload = json.dumps({"action": "catch"}).encode("utf-8") return urllib.request.Request( url, data=payload, headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", "Accept": "application/json", }, method="POST", ) ``` ### Technical Analysis The Skill must send an API credential to the user-configured pet backend, so authenticated network access is necessary for its declared functionality. However, `CATCH_API_URL` is accepted without validating its URL scheme, host, or redirect behavior. Consequently, an `http://` URL can receive the bearer credential over an unencrypted connection. The use of `urllib.request.urlopen()` also permits standard redirect handling without an explicit policy that requires redirects to remain on HTTPS and within the intended trust boundary. This does not constitute covert exfiltration: the documentation discloses the API request and bearer authentication. The vulnerability is that transport and destination safeguards are not enforced before sensitive information is transmitted. ### Attack Path 1. A malicious or mistaken configuration sets `CATCH_API_URL` to a plaintext HTTP endpoint. Alternatively, a configured endpoint responds with a redirect toward an unintended destination. 2. `load_config()` accepts the URL without scheme or destination validation. 3. `build_request()` places `API_KEY` in the `Authorization: Bearer` header ...[truncated 845 chars]
Remediation
## Remediation Suggestions 1. Parse `CATCH_API_URL` with `urllib.parse.urlsplit()` and require the `https` scheme before constructing the request. 2. Reject URLs with missing hosts, embedded user information, fragments, malformed ports, or unsupported schemes. 3. Disable automatic redirects or implement a custom redirect handler that permits a redirect only when: - the destination still uses HTTPS; - the destination host is explicitly trusted; - no downgrade to HTTP occurs; and - credentials are not forwarded across trust boundaries. 4. Prefer an explicit allowlist of backend hosts when the deployment model permits it. 5. Use a narrowly scoped, revocable API key that authorizes only required catch operations. 6. Keep production credentials in a protected secret store or environment variable rather than `_meta.json`. 7. Document the HTTPS-only requirement in `SKILL.md` and `references/api.md`. 8. Add tests confirming rejection of HTTP URLs, malformed URLs, HTTPS-to-HTTP redirects, and cross-host redirects. Example validation: ```python from urllib.parse import urlsplit def validate_api_url(url: str) -> str: parsed = urlsplit(url) if parsed.scheme.lower() != "https": raise ConfigError("CATCH_API_URL must use HTTPS.") if not parsed.hostname or parsed.username or parsed.password: raise ConfigError("CATCH_API_URL is invalid or contains embedded credentials.") if parsed.fragment: raise ConfigError("CATCH_API_URL must not contain a fragment.") return url ``` Apply this validation before passing the URL to `build_request()`, together with a restrictive redirect policy.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (6)

Tainted flow: 'req' from os.environ.get (line 53, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
def fetch_result(config: Dict[str, str]) -> Tuple[int, Dict[str, Any]]:
    req = build_request(config["CATCH_API_URL"], config["API_KEY"])
    try:
        with urllib.request.urlopen(req, timeout=20) as resp:
            status = getattr(resp, "status", 200)
            body = resp.read().decode("utf-8")
    except urllib.error.HTTPError as e:
Confidence
95% confidence
Finding
The script sends a bearer API key to a URL that is taken from environment variables or _meta.json without validating the destination or enforcing HTTPS. If an attacker can influence configuration, this becomes a server-side request/credential exfiltration issue: the skill will POST the secret to an arbitrary remote host. In this skill context, the whole purpose is to contact a remote backend, so configuration trust is security-critical and misuse is more dangerous than a generic network call.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
Use `scripts/catch_pet.py` for the actual API call. Prefer the script over re-implementing the request flow inline.

## Output Rules

- If a pet is caught, include rarity, name, level, and any short flavor text.
- If an item is caught, include item name, rarity, quantity, and description if present.
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill explicitly relies on environment variables, local file reads, and outbound network access, but it does not declare any tool scope or permission boundaries. That creates a least-privilege failure: an agent or platform may invoke the skill without clear review of its access needs, increasing the chance of unintended secret access or arbitrary remote calls.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The description says to use the skill whenever a user wants to trigger a remote catch action against a backend they control, which is broad and action-oriented enough to match casual requests. Because invocation causes a real network side effect, ambiguous routing can make the agent call a user-configured endpoint unexpectedly, potentially leaking metadata or triggering unintended external actions.

Vague Triggers

Medium
Confidence
95% confidence
Finding
Examples like "Try to fish" and "Go catch something for me" are vague and overlap with ordinary conversation, making accidental invocation plausible. In this skill, accidental invocation is more dangerous than in a read-only skill because it can perform authenticated network requests to a configurable external service.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This code performs an outbound HTTP POST and includes an Authorization bearer token, but the script provides no pre-request confirmation, user-facing notice, or explanatory comment/docstring about sending data and credentials to an external service. The later output only reports results after the fact, which does not satisfy the requirement for visible disclosure before or during the sensitive operation.

Static analysis

No suspicious patterns detected.