Back to skill

Security audit

X Smart Read

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do the X analytics it advertises, but its setup and credential handling create review-worthy security risk.

Review this skill before installing. It is coherent and uses the official X API, but install uv through a safer verified method, consider pinning dependencies or using a lockfile, run setup only in a private terminal, and grant the X app the minimum read/bookmark permissions you actually need.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T03 · Remote Payload Retrieval and Execution

Error
Location
SETUP.md:9
Finding
Remote Installer Is Downloaded and Executed Without Verification## Vulnerability Details **File Location**: `SETUP.md:7-10` and `SETUP.md:202-205` **Vulnerability Type**: Remote payload retrieval and immediate shell execution **Risk Level**: High ### Vulnerable Code ```bash - [uv](https://astral.sh/uv) — Python package runner (handles dependencies automatically) ```bash curl -LsSf https://astral.sh/uv/install.sh | sh ``` ``` The same command is repeated in the troubleshooting instructions: ```markdown ### "uv: command not found" - Install uv: `curl -LsSf https://astral.sh/uv/install.sh | sh` - Then restart your shell or run `source ~/.bashrc` ``` ### Technical Analysis The instructions pipe an HTTPS response directly into a shell. The retrieved installer is mutable and is neither pinned to a reviewed release nor verified with a cryptographic checksum or signature before execution. Use of Astral's official domain reduces the likelihood of a malicious payload but does not eliminate the trust risk. Compromise of the distribution service, publishing infrastructure, DNS/TLS path, or installer itself would change the code executed by users without requiring any modification to this repository. This behavior is not strictly necessary. The project could direct users to a versioned release package and require integrity verification before execution. ### Attack Path 1. An attacker compromises or gains control over the installer hosting or publishing infrastructure, or otherwise alters the response served from `https://astral.sh/uv/install.sh`. 2. A user follows the project setup instructions. 3. `curl` retrieves the attacker-controlled response. 4. The pipe sends the response directly to `sh` without review or integrity validation. 5. The payload executes with the privileges of the invoking user. 6. The payload can access files available to that user, including OpenClaw configuration, X credentials, project files, and other user data. ### Impact Assessment Suc ...[truncated 392 chars]
Remediation
## Remediation Suggestions - Remove all `curl | sh` instructions. - Direct users to a specific, versioned `uv` release rather than a mutable installer endpoint. - Require verification against a checksum published through an independent, authenticated release channel. - Prefer signed operating-system packages or official package-manager installation methods. - If a script-based installation remains necessary, split download and execution into separate steps: ```bash curl -fL -o uv-installer.sh https://example.invalid/versioned/uv-installer.sh echo "EXPECTED_SHA256 uv-installer.sh" | sha256sum --check - less uv-installer.sh sh uv-installer.sh ``` - Pin the URL to an immutable release artifact and document how users can verify its signature.

T08 · Insecure Dependencies

Warning
Location
scripts/x_setup.py:2
Finding
Automatically Installed Dependency Is Not Locked to a Reproducible Version## Vulnerability Details **File Location**: `scripts/x_setup.py:2-7` and equivalent inline metadata in the other executable scripts; `AGENTS.md:16` **Vulnerability Type**: Unpinned automatically resolved third-party dependency **Risk Level**: Medium ### Vulnerable Code ```python # /// script # requires-python = ">=3.10" # dependencies = [ # "tweepy>=4.14.0", # ] # /// ``` The documented execution model automatically installs dependencies: ```markdown All scripts use `uv run` (auto-installs dependencies). Run from the skill directory. ``` ### Technical Analysis The constraint `tweepy>=4.14.0` accepts any future Tweepy release that satisfies the lower bound. The repository contains no reviewed lockfile, exact version pin, or package hash. As a result, two executions at different times may resolve different dependency code. Tweepy executes in the same Python process as the Skill and receives the user's X API key, API secret, access token, access-token secret, and bearer token. A compromised dependency release would consequently run in a particularly sensitive context. This finding does not establish that the current Tweepy package is malicious. The vulnerability is the mutable and non-reproducible dependency resolution process. ### Attack Path 1. An attacker compromises the package publisher account, package registry, release pipeline, or a future compatible Tweepy release. 2. A malicious version satisfying `tweepy>=4.14.0` is published. 3. A user invokes a script with `uv run`. 4. `uv` resolves and installs the malicious compatible version because no lockfile or exact version prevents the update. 5. The malicious package executes when imported. 6. During setup or normal operation, it can access X credentials passed into `tweepy.Client` and any files available to the invoking user. ### Impact Assessment Exploitation can provide arbitrary Python code execution under the user's account. Because ...[truncated 332 chars]
Remediation
## Remediation Suggestions - Commit a reviewed `uv.lock` file that resolves exact dependency versions. - Replace open-ended lower-bound declarations with reviewed, exact versions where inline script dependencies must be used. - Use package hashes or signature verification where supported. - Apply the same locked dependency policy consistently to every executable script. - Update dependencies through an explicit review process that includes changelog inspection, vulnerability scanning, and test execution. - Consider centralizing dependencies in a locked project configuration rather than independently resolving inline metadata for each script. - Configure automated dependency updates to create reviewable changes rather than silently accepting future releases at runtime.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/x_setup.py:100
Finding
Interactive Credential Entry Echoes Secrets to the Terminal## Vulnerability Details **File Location**: `scripts/x_setup.py:100-107` **Vulnerability Type**: Sensitive credential exposure through visible terminal input **Risk Level**: Medium ### Vulnerable Code ```python else: print("No .env credentials found. Enter your X API keys:") print("(Get them at https://developer.x.com)") print() api_key = input("API Key (Consumer Key): ").strip() api_secret = input("API Secret (Consumer Secret): ").strip() access_token = input("Access Token: ").strip() access_secret = input("Access Token Secret: ").strip() bearer_token = input("Bearer Token (optional, press Enter to skip): ").strip() ``` ### Technical Analysis Python's `input()` function echoes typed characters to the terminal. It is unsuitable for API secrets, access-token secrets, and bearer tokens. Credentials may be exposed to nearby observers, screen-sharing participants, terminal session recorders, remote administration logs, or captured demonstration output. The setup script does not intentionally print the resulting credential values, and the saved configuration is initially assigned mode `0600`. Those protections do not address disclosure while credentials are being entered. ### Attack Path 1. A user runs the interactive setup flow because no suitable credentials are found in `~/.openclaw/.env`. 2. The user enters the API key, API secret, access token, access-token secret, and bearer token. 3. Each value appears visibly in the terminal because `input()` enables echo. 4. An observer, screen recorder, terminal logging facility, or shared-session participant captures the displayed values. 5. The captured credentials are used to authenticate to X within the permissions granted to the associated application and user tokens. ### Impact Assessment Disclosure can permit unauthorized X API access and consumption of the user's paid API credits. Depending on the permissions assigned to the ...[truncated 401 chars]
Remediation
## Remediation Suggestions - Use `getpass.getpass()` for every secret value: ```python from getpass import getpass api_key = getpass("API Key (Consumer Key): ").strip() api_secret = getpass("API Secret (Consumer Secret): ").strip() access_token = getpass("Access Token: ").strip() access_secret = getpass("Access Token Secret: ").strip() bearer_token = getpass("Bearer Token (optional, press Enter to skip): ").strip() ``` - Consider treating the API key as sensitive as well, even where a provider does not classify it as a standalone secret. - Warn users not to run credential setup in recorded, shared, or screen-broadcast terminal sessions. - Prefer an operating-system credential store or keyring over long-term plaintext JSON storage when available. - Preserve restrictive permissions after every configuration rewrite and verify that both the configuration directory and file are inaccessible to other users. - Add tests confirming that secret prompts disable terminal echo and that redacted configuration output never reveals credential material.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (47)

Self-Modification

High
Category
Rogue Agent
Content
1. Fork the repo
2. Create a feature branch
3. Add your command + update SKILL.md, AGENTS.md, README.md command table
4. Run the testing checklist above
5. Open a PR with a description of what the command does and its API cost
Confidence
85% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Anti-Refusal Statement

High
Category
Anti-Refusal
Content
- **Guarded** (default) — warns you and stops when you hit your daily limit
- **Relaxed** — warns you but keeps going
- **Unlimited** — no limits, no warnings

Every command also supports `--dry-run` to preview what it would cost before making any API calls.
Confidence
80% confidence
Finding
Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Chaining Abuse

High
Category
Tool Misuse
Content
- [uv](https://astral.sh/uv) — Python package runner (handles dependencies automatically)
  ```bash
  curl -LsSf https://astral.sh/uv/install.sh | sh
  ```
- An X (Twitter) account
- $5 minimum to load API credits (see Step 4)
Confidence
96% confidence
Finding
Piping `curl` output into `sh` creates an immediate command-execution chain from untrusted network content to the shell. In the context of a setup guide for a skill that later handles API tokens, compromise here could lead to host takeover and theft of all imported credentials.

Credential Access

High
Category
Privilege Escalation
Content
- **API Key Secret** (also called Consumer Secret) — looks like: `g9NNNTOi...`
4. Save these somewhere safe — you can't see them again

### Access Token & Secret (User Auth)

1. On the same **Keys and tokens** page, scroll to **Authentication Tokens**
2. Under **Access Token and Secret**, click **Generate**
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- **API Key Secret** (also called Consumer Secret) — looks like: `g9NNNTOi...`
4. Save these somewhere safe — you can't see them again

### Access Token & Secret (User Auth)

1. On the same **Keys and tokens** page, scroll to **Authentication Tokens**
2. Under **Access Token and Secret**, click **Generate**
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- **API Key Secret** (also called Consumer Secret) — looks like: `g9NNNTOi...`
4. Save these somewhere safe — you can't see them again

### Access Token & Secret (User Auth)

1. On the same **Keys and tokens** page, scroll to **Authentication Tokens**
2. Under **Access Token and Secret**, click **Generate**
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- **API Key Secret** (also called Consumer Secret) — looks like: `g9NNNTOi...`
4. Save these somewhere safe — you can't see them again

### Access Token & Secret (User Auth)

1. On the same **Keys and tokens** page, scroll to **Authentication Tokens**
2. Under **Access Token and Secret**, click **Generate**
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- **API Key Secret** (also called Consumer Secret) — looks like: `g9NNNTOi...`
4. Save these somewhere safe — you can't see them again

### Access Token & Secret (User Auth)

1. On the same **Keys and tokens** page, scroll to **Authentication Tokens**
2. Under **Access Token and Secret**, click **Generate**
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- **API Key Secret** (also called Consumer Secret) — looks like: `g9NNNTOi...`
4. Save these somewhere safe — you can't see them again

### Access Token & Secret (User Auth)

1. On the same **Keys and tokens** page, scroll to **Authentication Tokens**
2. Under **Access Token and Secret**, click **Generate**
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- **API Key Secret** (also called Consumer Secret) — looks like: `g9NNNTOi...`
4. Save these somewhere safe — you can't see them again

### Access Token & Secret (User Auth)

1. On the same **Keys and tokens** page, scroll to **Authentication Tokens**
2. Under **Access Token and Secret**, click **Generate**
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- **API Key Secret** (also called Consumer Secret) — looks like: `g9NNNTOi...`
4. Save these somewhere safe — you can't see them again

### Access Token & Secret (User Auth)

1. On the same **Keys and tokens** page, scroll to **Authentication Tokens**
2. Under **Access Token and Secret**, click **Generate**
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The code chunk’s primary function is narrow: read any tweet or thread and optionally fetch related conversation posts, while storing results locally and enforcing budget checks. This does align with the 'read any tweet/thread' and 'persistent local store and daily budget guards' parts of the description. However, the declared description presents a substantially broader analytics/monitoring capability set—timeline engagement, mentions, follower tracking, bookmarks, and combined briefings—that is not implemented in this code chunk. Because the supplied code does not reflect most of the advertised functionality and instead only covers one sub-feature, the description does not accurately represent the actual behavior of this code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The code is focused narrowly on the user's own timeline/posts and engagement metrics. It does match parts of the description: timeline engagement, persistent local store, and daily budget guards. However, the declared description promises several additional capabilities that are not present in this code chunk, including mentions, follower tracking, reading any tweet/thread, bookmarks, and combined briefings. Displaying bookmark_count as a metric on tweets is not the same as supporting bookmark access. Because the actual implemented functionality is materially narrower than the declared purpose, this is a description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The declared description presents a broad personal X analytics tool with multiple features: timeline engagement, mentions, follower tracking, reading tweets/threads, bookmarks, and combined briefings. The supplied code only implements a narrow subset: profile lookup for self or another user and optional follower-count history tracking for the authenticated user, plus budget/cost handling. Follower tracking and persistent local storage are consistent with the description, but most of the advertised capabilities are absent from this code chunk. That makes the code's actual behavior materially narrower than the declared purpose.

Anti-Refusal Statement

High
Category
Anti-Refusal
Content
The user can set a budget enforcement mode via `x_setup.py --budget-mode`:
- **guarded** (default): Warn at 50/80/100%, block at limit
- **relaxed**: Warn at 50/80/100%, never block
- **unlimited**: No warnings, no blocks

### Budget Tiers
Confidence
83% confidence
Finding
Offering an `unlimited` budget mode described as having 'No warnings, no blocks' weakens a safety guard around paid API usage. While not malicious by itself, normalizing the removal of warnings increases the chance of accidental overspend or agent misuse, especially when combined with broad triggers and shell access.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
| Batch Get Tweets | `GET /2/tweets?ids=id1,id2,...` | Bearer/OAuth | ~$0.005 |
| Search Recent | `GET /2/tweets/search/recent` | Bearer | ~$0.005 |
| Create Tweet | `POST /2/tweets` | OAuth 1.0a | Free |
| Delete Tweet | `DELETE /2/tweets/:id` | OAuth 1.0a | Free |
| Get Bookmarks | `GET /2/users/:id/bookmarks` | OAuth 1.0a | ~$0.005 |
| Bookmark Tweet | `POST /2/users/:id/bookmarks` | OAuth 1.0a | Free |
| Remove Bookmark | `DELETE /2/users/:id/bookmarks/:tweet_id` | OAuth 1.0a | Free |
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
| Delete Tweet | `DELETE /2/tweets/:id` | OAuth 1.0a | Free |
| Get Bookmarks | `GET /2/users/:id/bookmarks` | OAuth 1.0a | ~$0.005 |
| Bookmark Tweet | `POST /2/users/:id/bookmarks` | OAuth 1.0a | Free |
| Remove Bookmark | `DELETE /2/users/:id/bookmarks/:tweet_id` | OAuth 1.0a | Free |
| Usage Stats | `GET /2/usage/tweets` | Bearer | Free |

## Tweet Fields
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Credential Access

High
Category
Privilege Escalation
Content
| Method | When | Keys Needed |
|--------|------|-------------|
| OAuth 1.0a (User Context) | Own tweets, mentions, get_me, posting, bookmarks | API Key + Secret + Access Token + Secret |
| Bearer Token (App Context) | Public user lookup, public tweets, search | Bearer Token only |

OAuth 1.0a is required for `impression_count` on your own tweets and all write actions (posting, bookmarking).
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
sys.path.insert(0, str(Path(__file__).resolve().parent))
from x_common import CONFIG_DIR, CONFIG_PATH, DATA_DIR, USAGE_PATH, VERSION

ENV_PATH = Path.home() / ".openclaw" / ".env"

BUDGET_TIERS = {
    "lite": {"daily_budget": 0.03, "desc": "Morning brief only, ~$0.50/mo"},
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Anti-Refusal Statement

High
Category
Anti-Refusal
Content
BUDGET_MODES = {
    "guarded": "Warn at 50/80/100%, block at limit (default)",
    "relaxed": "Warn at 50/80/100%, never block",
    "unlimited": "No warnings, no blocks",
}
Confidence
80% confidence
Finding
Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Anti-Refusal Statement

High
Category
Anti-Refusal
Content
BUDGET_MODES = {
    "guarded": "Warn at 50/80/100%, block at limit (default)",
    "relaxed": "Warn at 50/80/100%, never block",
    "unlimited": "No warnings, no blocks",
}
Confidence
80% confidence
Finding
Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Credential Access

High
Category
Privilege Escalation
Content
def load_env(path: Path) -> dict[str, str]:
    """Parse a simple KEY=VALUE .env file."""
    env = {}
    if not path.exists():
        return env
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
def load_env(path: Path) -> dict[str, str]:
    """Parse a simple KEY=VALUE .env file."""
    env = {}
    if not path.exists():
        return env
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
def load_env(path: Path) -> dict[str, str]:
    """Parse a simple KEY=VALUE .env file."""
    env = {}
    if not path.exists():
        return env
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
def load_env(path: Path) -> dict[str, str]:
    """Parse a simple KEY=VALUE .env file."""
    env = {}
    if not path.exists():
        return env
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Static analysis

No suspicious patterns detected.