Back to skill

Security audit

TrendProof

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent TrendProof API helper, but it handles API credentials in ways users should review before installing.

Install only if you are comfortable giving the skill a TrendProof API key and sending your keyword queries to TrendProof. Prefer using a temporary environment variable or a limited API key instead of saving the key, avoid setting TRENDPROOF_BASE_URL unless you trust the endpoint, and check local config-file permissions if you use configure.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/trendproof.py:59
Finding
API Credentials Can Be Forwarded to an Arbitrary Environment-Controlled Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/trendproof.py`, lines 59–79 **Vulnerability Type**: Unrestricted destination for authenticated network requests **Risk Level**: Medium ### Vulnerable Code ```python def _get_base_url() -> str: return os.environ.get("TRENDPROOF_BASE_URL", DEFAULT_BASE_URL).rstrip("/") # ── HTTP ──────────────────────────────────────────────────────────────────── def _post(endpoint: str, body: dict, api_key: str | None) -> dict: base = _get_base_url() url = f"{base}{endpoint}" data = json.dumps(body).encode() headers = {"Content-Type": "application/json", "Accept": "application/json"} if api_key: headers["Authorization"] = f"Bearer {api_key}" req = urllib.request.Request(url, data=data, headers=headers, method="POST") try: with urllib.request.urlopen(req, timeout=30) as resp: return json.loads(resp.read()) ``` ### Technical Analysis The request destination is obtained from the `TRENDPROOF_BASE_URL` environment variable without validating its scheme, hostname, port, or origin. The `_post` function subsequently adds the user's TrendProof API key to the `Authorization` header for requests sent to that destination. Consequently, an environment override can cause the script to disclose both the API credential and submitted keyword data to a server other than the documented `https://trendproof.dev` service. Because the base URL can include an arbitrary scheme and host accepted by `urllib`, the code does not preserve the intended trust boundary around the credential. An endpoint override may be useful during development, but unrestricted overrides are not required for the Skill's declared production functionality. Production credentials should not be attached to requests sent to untrusted origins. ### Attack Path 1. An attacker influences the environment used to launch the Skill, such as through a compromised wrapper, automation configuration, shell profil ...[truncated 1129 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin production requests to the documented origin: ```python DEFAULT_BASE_URL = "https://trendproof.dev" ``` 2. Remove `TRENDPROOF_BASE_URL` support in production, or validate the parsed URL before constructing a request: - Require the `https` scheme. - Require the exact allowlisted hostname `trendproof.dev`. - Reject embedded credentials, fragments, unexpected ports, and ambiguous hostnames. - Normalize and compare the parsed origin rather than relying on string prefixes. 3. If endpoint overrides are necessary for testing: - Require an explicit development-only flag. - Refuse to send a production API key to a non-allowlisted origin. - Use separate test credentials. - Display a clear warning before making the request. 4. Consider constructing URLs from a fixed trusted origin and allowlisting endpoint paths such as `/api/analyze` and `/api/related`. 5. Add automated tests confirming that malformed URLs, HTTP URLs, subdomain lookalikes, and arbitrary external hosts are rejected. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/trendproof.py:46
Finding
API Key Is Stored Without Enforced Owner-Only File Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/trendproof.py`, lines 46–49 and 180–182 **Vulnerability Type**: Insecure plaintext credential storage permissions **Risk Level**: Medium ### Vulnerable Code The configuration writer does not assign restrictive permissions: ```python def _write_config(data: dict) -> None: CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True) CONFIG_PATH.write_text(json.dumps(data, indent=2)) ``` The API key is then persisted through that writer: ```python cfg = _read_config() cfg["api_key"] = args.api_key _write_config(cfg) ``` ### Technical Analysis The `configure` command stores the TrendProof API key in plaintext at `~/.config/clawdbot/trendproof.json` or beneath the environment-selected `XDG_CONFIG_HOME`. The script uses `Path.write_text` without explicitly setting the file to owner-only permissions. Permissions therefore depend on the process umask and any existing file or directory permissions. Under a common umask of `022`, a newly created file can be readable by users other than its owner if the surrounding directories permit traversal. The code also does not verify ownership, reject symbolic links, repair an existing overly permissive file, or use an atomic owner-only file creation procedure. Plaintext credential storage may be necessary when no operating-system credential store is available, but enforcing least-privilege access to the stored secret is necessary. ### Attack Path 1. A user runs: ```bash python3 scripts/trendproof.py configure --api-key TRND_SECRET ``` 2. The process has a permissive umask, the configuration directory is accessible to other local users, or the destination file already has broad permissions. 3. `_write_config` writes the API key without enforcing mode `0600`. 4. Another local account or process reads the configuration file: ```bash cat ~/.config/clawdbot/trendproof.json ``` 5. The attacker extracts the plaintext API key and uses it against th ...[truncated 734 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the configuration directory with owner-only permissions (`0700`) and verify its owner before use. 2. Create the credential file atomically with mode `0600`, for example by using `os.open` with `O_CREAT | O_EXCL | O_WRONLY` and an explicit mode. 3. When updating an existing file: - Verify that it is a regular file owned by the current user. - Reject symbolic links. - Write to a securely created temporary file in the same directory. - Set mode `0600`. - Atomically replace the destination. 4. Repair or reject existing configuration files that are group-readable or world-readable. 5. Prefer an operating-system credential store or secret-management service where available. If plaintext storage remains supported, document its location and security requirements. 6. Avoid accepting secrets directly on the command line where possible because command-line arguments can be exposed through shell history or process inspection. Prefer secure interactive input, environment injection from a secret manager, or standard input with appropriate safeguards. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (4)

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill instructs the agent to use environment access, file write, and network capabilities to configure and call an external API, but it does not declare any explicit tool scope or allowed-tools restrictions. This creates an over-privileged integration pattern where a runtime may grant broader capabilities than intended, increasing the risk of secret handling mistakes or unintended outbound access.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Analyze
curl -s https://trendproof.dev/api/analyze \
  -H "Authorization: Bearer TRND_xxxxx" \
  -H "Content-Type: application/json" \
  -d '{"keyword": "AI agents"}'
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The manifest describes a skill for querying TrendProof and returning keyword trend data, but this file also creates and writes a local config file to persist API credentials. Persisting secrets on disk is a materially broader behavior than transient keyword analysis and is not mentioned in the stated skill description.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The `configure` command saves and displays API keys, which is an operational credential-management feature rather than a direct keyword trend analysis capability. That capability is not justified by the manifest's stated purpose of analyzing keywords, comparing niches, and suggesting related terms.

Static analysis

No suspicious patterns detected.