Back to skill

Security audit

Ryot

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it advertises for Ryot media tracking, with clear but important credential and scheduled-notification risks users should understand.

Install only if you are comfortable giving the skill a Ryot API token. Use a trusted HTTPS Ryot URL, protect /home/node/clawd/config/ryot.json with private permissions, and review the optional cron/WhatsApp jobs before enabling them because they will continue sending report output until removed. Commands such as complete, review, collection create/add, and bulk episode marking change your Ryot account data.

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

Error
Location
scripts/ryot_api.py:21
Finding
Bearer Token May Be Transmitted to an Untrusted or Unencrypted Endpoint<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/ryot_api.py:21-43` - `scripts/ryot-mark-episodes.py:19-42` - `scripts/ryot_calendar.py:18-31` - `scripts/ryot_collections.py:15-30` - `scripts/ryot_reviews.py:15-30` - `scripts/ryot_stats.py:15-30` **Vulnerability Type**: Unvalidated destination for authenticated network requests **Risk Level**: High ### Vulnerable Code The following representative implementation appears in `scripts/ryot_api.py`: ```python def graphql_request(query, variables=None): """Execute a GraphQL request to Ryot API.""" config = load_config() url = f"{config['url']}/backend/graphql" headers = { "Content-Type": "application/json", "Authorization": f"Bearer {config['api_token']}", "User-Agent": "Ryot-API-Client/1.0" } data = {"query": query} if variables: data["variables"] = variables req = urllib.request.Request( url, data=json.dumps(data).encode(), headers=headers, method="POST" ) with urllib.request.urlopen(req) as response: return json.loads(response.read().decode()) ``` The other listed scripts use the same security-sensitive pattern: the configured URL is concatenated with `/backend/graphql`, and the API token is placed in the `Authorization` header without validating the URL scheme or destination. ### Technical Analysis The scripts trust the `url` value loaded from `/home/node/clawd/config/ryot.json`. They do not parse the URL or enforce HTTPS before attaching the reusable bearer token. If the configuration contains an `http://` URL, the authorization header and private GraphQL data can be transmitted without transport encryption. A network attacker capable of observing or modifying that connection may recover the token. If the configuration is modified to reference an attacker-controlled server, invoking any affected command causes the token to be sent directly to that server. This is especially ...[truncated 1796 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse and validate the configured URL before creating the request: ```python from urllib.parse import urlsplit def validate_base_url(value): parsed = urlsplit(value) if parsed.scheme != "https": raise ValueError("The Ryot URL must use HTTPS") if not parsed.hostname: raise ValueError("The Ryot URL must contain a valid hostname") if parsed.username or parsed.password: raise ValueError("Embedded URL credentials are not allowed") if parsed.query or parsed.fragment: raise ValueError("Query strings and fragments are not allowed") return value.rstrip("/") ``` 2. Use the validated value consistently in every script: ```python base_url = validate_base_url(config["url"]) url = f"{base_url}/backend/graphql" ``` 3. If local development requires HTTP, allow it only through an explicit opt-in setting and restrict it to approved loopback addresses such as `127.0.0.1` or `::1`. 4. Consider an optional hostname allowlist or display the resolved destination before first use. 5. Add a finite network timeout: ```python with urllib.request.urlopen(req, timeout=30) as response: ... ``` 6. Avoid forwarding authorization headers across redirects. Prefer rejecting redirects or verifying that the redirect destination has the same HTTPS origin before resending credentials. 7. Centralize configuration and request handling in one reviewed module so all scripts receive identical validation and transport protections. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:24
Finding
Plaintext API Token Storage Is Documented Without Restrictive File Permissions<![CDATA[ ## Vulnerability Details **File Locations**: - `SKILL.md:24-31` - `SKILL.md:173-176` - `PUBLISHING.md:21-29` **Vulnerability Type**: Insecure storage guidance for a reusable API credential **Risk Level**: Medium ### Vulnerable Documentation `SKILL.md` instructs users to create a plaintext configuration containing the API token: ```markdown 1. **Create config file** at `/home/node/clawd/config/ryot.json`: ```json { "url": "https://your-ryot-instance.com", "api_token": "your_api_token_here" } ``` ``` It later instructs the agent to create the same file when it is absent: ```markdown - **Before first use:** Check if `/home/node/clawd/config/ryot.json` exists. If not, ask the user for their Ryot instance URL and API token, then create the config file. ``` `PUBLISHING.md` repeats the configuration instructions: ```markdown Users need to create `/home/node/clawd/config/ryot.json`: ```json { "url": "https://your-ryot-instance.com", "api_token": "YOUR_API_TOKEN_HERE" } ``` ``` No restrictive permissions, ownership checks, or secret-storage controls are specified. ### Technical Analysis The API token is a reusable bearer credential. Anyone who obtains it may act with the token holder's Ryot API privileges. The documented setup stores this credential in a fixed plaintext file but does not require that its containing directory be private or that the file use mode `0600`. Actual exposure depends on the user's umask, file-creation method, directory permissions, and local threat model. On a multi-user system or in an environment containing unrelated processes, permissive file permissions can expose the token. The scripts also read the file without verifying its owner, permission mode, symlink status, or whether it is writable by other users. This increases the risk of credential disclosure or endpoint substitution when the surrounding environment is not fully trusted. ### Attack Path 1. The user or agent follows the documented setup and crea ...[truncated 1209 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Update the setup instructions to create a private configuration directory and file: ```bash install -d -m 700 /home/node/clawd/config install -m 600 /dev/null /home/node/clawd/config/ryot.json ``` 2. After writing the configuration, explicitly enforce permissions: ```bash chmod 600 /home/node/clawd/config/ryot.json ``` 3. Ensure the file is owned by the account that runs the Skill and that the parent directory is not writable by unrelated users. 4. Before reading the configuration, verify that: - The file is a regular file and not a symlink. - It has the expected owner. - Group and other permission bits do not permit reading or writing. - The parent directory is not writable by unintended users. 5. Prefer an OpenClaw-supported credential store, environment-injected secret, or operating-system secret manager instead of a plaintext JSON token where available. 6. Never print the token in normal output, logs, error messages, or scheduled report content. 7. Recommend narrowly scoped, revocable API tokens and document a token-rotation process for suspected disclosure. ]]>
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 (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
This mismatch includes materially different behavior: creating scheduled automations and configuring WhatsApp delivery, which introduces persistent outbound messaging beyond ordinary media tracking. Hidden or under-disclosed automation and third-party notification channels increase the risk of unanticipated data sharing, spam, and ongoing actions after initial setup.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
This mismatch includes materially different behavior: creating scheduled automations and configuring WhatsApp delivery, which introduces persistent outbound messaging beyond ordinary media tracking. Hidden or under-disclosed automation and third-party notification channels increase the risk of unanticipated data sharing, spam, and ongoing actions after initial setup.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
This mismatch includes materially different behavior: creating scheduled automations and configuring WhatsApp delivery, which introduces persistent outbound messaging beyond ordinary media tracking. Hidden or under-disclosed automation and third-party notification channels increase the risk of unanticipated data sharing, spam, and ongoing actions after initial setup.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This mismatch includes materially different behavior: creating scheduled automations and configuring WhatsApp delivery, which introduces persistent outbound messaging beyond ordinary media tracking. Hidden or under-disclosed automation and third-party notification channels increase the risk of unanticipated data sharing, spam, and ongoing actions after initial setup.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
This mismatch includes materially different behavior: creating scheduled automations and configuring WhatsApp delivery, which introduces persistent outbound messaging beyond ordinary media tracking. Hidden or under-disclosed automation and third-party notification channels increase the risk of unanticipated data sharing, spam, and ongoing actions after initial setup.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This mismatch includes materially different behavior: creating scheduled automations and configuring WhatsApp delivery, which introduces persistent outbound messaging beyond ordinary media tracking. Hidden or under-disclosed automation and third-party notification channels increase the risk of unanticipated data sharing, spam, and ongoing actions after initial setup.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
This mismatch includes materially different behavior: creating scheduled automations and configuring WhatsApp delivery, which introduces persistent outbound messaging beyond ordinary media tracking. Hidden or under-disclosed automation and third-party notification channels increase the risk of unanticipated data sharing, spam, and ongoing actions after initial setup.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill documentation explicitly directs use of Python scripts against a remote GraphQL API and references reading a local config file with credentials, but the manifest declares no tool scope or allowed-tools. This creates a transparency and containment problem: an agent may perform authenticated network actions and local file access without the permission boundary being clearly declared to users or the platform.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The automated setup enables recurring reports and WhatsApp delivery without prominently warning that the skill will continue sending outbound notifications and sharing data on a schedule. In context, persistence and external delivery make this more dangerous because a one-time setup can create long-lived data flows the user may not fully understand or remember.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
Adding WhatsApp delivery expands the skill's data exposure to an external messaging platform not central to the stated Ryot tracking function. Without clear justification and consent, users may unknowingly route media activity, schedules, or account-linked information to a third party.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The instructions tell the agent to solicit and store a user's API token in a local file without any warning about credential sensitivity, storage risks, or least-privilege handling. In an agent context, this is dangerous because it normalizes collecting secrets through conversational flow and persisting them on disk, increasing the chance of leakage or misuse.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This code loads an API token from local configuration and sends it in an HTTP Authorization header to a remote GraphQL endpoint. While the script's purpose is to fetch calendar data, there is no visible warning, log message, or explanatory comment disclosing that it reads credentials and transmits data over the network.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This code accesses sensitive credentials via the config file and transmits them as a bearer token in an HTTP request. Although the behavior is functional, there is no visible warning, prompt, or explanatory comment/docstring informing the user that credentials will be used for authenticated network calls.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The create_collection function performs a remote state-changing GraphQL mutation using stored credentials with no confirmation, dry-run mode, or explicit user disclosure at the point of action. In an agent-skill context, this can cause silent modification of a user's remote account data, which is more dangerous because users may invoke higher-level automation without realizing it will create persistent server-side objects.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The add_to_collection function issues a remote mutation that alters user data by adding media metadata to a collection, again without confirmation or clear warning. In the context of an agent skill that may be invoked programmatically, undisclosed write actions increase the risk of unintended bulk or repeated modifications to a user's account and can be abused if the skill is triggered deceptively.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
This code performs an authenticated HTTP POST to a remote GraphQL endpoint, transmitting metadata identifiers, ratings, and optional review text. While the script prints a success message after completion, it does not provide any prior user-facing disclosure in code comments, docstrings, or prompts that local input will be sent to a server.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The script loads an API token from local configuration and sends it in an Authorization header during GraphQL requests. While this behavior is functionally expected for the integration, the file contains no confirmation prompt and no user-facing warning or explanatory comment/docstring disclosing that credentials and usage data are sent over the network.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The string literal instructs the system to respond in Italian ('Esegui lo script ... e inviami l'output...'), which imposes a specific language on generated output. The script does not offer any language selection or document a region-specific reason for this constraint, making it a natural-language policy violation.

Missing User Warnings

Low
Confidence
94% confidence
Finding
The publishing guide instructs users to store an API token in `/home/node/clawd/config/ryot.json` in plaintext without any warning about file permissions, secret handling, or safer storage options. This can lead to accidental disclosure through backups, logs, shared systems, or overly permissive filesystem access, especially on multi-user hosts.

Context-Inappropriate Capability

Low
Confidence
76% confidence
Finding
The manifest says the skill requires an existing config file containing the Ryot URL and API token, but the operational note directs the agent to ask for credentials and create `/home/node/clawd/config/ryot.json` if it does not exist. Creating and persisting credentials on disk is a separate capability beyond the core media-tracking purpose described in the manifest.

Static analysis

No suspicious patterns detected.