Back to skill

Security audit

X

Security checks for vulnerabilities and agentic risk

Overview

This X API skill is mostly coherent, but it stores powerful account tokens in local plaintext files and can read private bookmarks or post publicly without strong safeguards.

Install only if you are comfortable granting this skill X API access that may include private bookmarks and public posting. Use a least-privilege X app if possible, set spending limits, restrict ~/.openclaw/x permissions to owner-only, keep the JSON files out of backups and repositories, and manually confirm any post text before running the post command.

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/x.py:62
Finding

Credential and OAuth token files are created without restrictive permissions

Content
View full analysis
~/.openclaw/x/credentials.json < ~/.openclaw/x/credentials.json <
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/x.py:264
Finding

OAuth callback uses a predictable state value and does not validate it

Content
View full analysis
Authenticated! You can close this tab.") ``` ### Technical Analysis OAuth `state` must be unpredictable, bound to the current authorization transaction, and validated when the callback is received. This implementation always sends the literal value `"state"` and does not read or compare the callback's `state` parameter. The callback also accepts every path beginning with `/callback`, rather than requiring the exact callback path. Because the HTTP server handles only one request, an unsolicited request can consume the callback before the legitimate authorization redirect arrives. PKCE is correctly used and significantly limits authorization-code substitution because a code must match the locally generated verifier. However, PKCE does not replace state validation. The missing check still permits callback injection, authorization-flow disruption, and failure to establish that the response belongs to the initiated browser transaction. ### Attack Path 1. The victim runs `pyth ...[truncated 1168 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (27)

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

The guide instructs users to place a live bearer token in a plaintext JSON file under the home directory. While this is common setup guidance, storing reusable API credentials unencrypted on disk increases the risk of credential theft by other local users, malware, backups, or accidental disclosure.

Content

Scanner excerpt · SETUP.md (reported line 35)May include surrounding context.

bash
   mkdir -p ~/.openclaw/x
   cat > ~/.openclaw/x/credentials.json <<EOF
   {
     "bearer_token": "YOUR_BEARER_TOKEN_HERE",
     "consumer_key": "OPTIONAL",

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

The documented file structure explicitly identifies several local files that contain bearer, client, and user OAuth tokens. That centralization of plaintext secrets is operationally convenient but increases exposure if the workstation, shell environment, or backups are compromised.

Content

Scanner excerpt · SETUP.md (reported line 182)May include surrounding context.

text
~/.openclaw/x/
├── credentials.json    # Bearer token (required)
├── oauth2.json         # OAuth client creds (optional)
└── tokens.json         # OAuth user tokens (auto-generated)

Context Leakage

High
Category
Data Exfiltration
Confidence
75% confidence
Finding

Code or instructions that leak agent conversation context to external services, potentially exposing sensitive user interactions.

Content

Scanner excerpt · SKILL.md (reported line 4)May include surrounding context.

md
---
name: x
version: 1.0.0
description: "Access X (Twitter) via API v2: user profiles, timelines, threads, search, bookmarks, likes, and posting. Use when asked to: (1) get user info or profile, (2) fetch someone's tweets/timeline, (3) extract conversation threads, (4) search for tweets about a topic, (5) retrieve bookmarks, (6) get liked tweets, (7) post tweets, or (8) lookup tweets by ID or URL."
summary: "X (Twitter) API v2 client — profiles, timelines, search, bookmarks, posting."
metadata:
  openclaw:

Context Leakage

High
Category
Data Exfiltration
Confidence
75% confidence
Finding

Code or instructions that leak agent conversation context to external services, potentially exposing sensitive user interactions.

Content

Scanner excerpt · SKILL.md (reported line 147)May include surrounding context.

python3 {baseDir}/scripts/x.py search "OpenClaw" --max 100

text

**Extract threads:**
```bash
# Get full thread for analysis
python3 {baseDir}/scripts/x.py thread <tweet_url> > thread.txt

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The documentation explicitly directs users to create a plaintext credentials file containing a bearer token. This creates a real credential-exposure risk because bearer tokens are reusable secrets that can grant API access if read by other local users, malware, backups, logs, or accidentally shared files.

Content

Scanner excerpt · references/quickstart.md (reported line 8)May include surrounding context.

bash
# 1. Create credentials file
mkdir -p ~/.openclaw/x
cat > ~/.openclaw/x/credentials.json <<EOF
{
  "bearer_token": "YOUR_BEARER_TOKEN_HERE"
}

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · SETUP.md (reported line 199)May include surrounding context.

md
from datetime import datetime

CONFIG_DIR = os.path.expanduser("~/.openclaw/x")
CREDS_FILE = os.path.join(CONFIG_DIR, "credentials.json")
OAUTH2_FILE = os.path.join(CONFIG_DIR, "oauth2.json")
TOKENS_FILE = os.path.join(CONFIG_DIR, "tokens.json")
API_BASE = "https://api.x.com/2"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/x.py (reported line 29)May include surrounding context.

python
from datetime import datetime

CONFIG_DIR = os.path.expanduser("~/.openclaw/x")
CREDS_FILE = os.path.join(CONFIG_DIR, "credentials.json")
OAUTH2_FILE = os.path.join(CONFIG_DIR, "oauth2.json")
TOKENS_FILE = os.path.join(CONFIG_DIR, "tokens.json")
API_BASE = "https://api.x.com/2"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/x.py (reported line 53)May include surrounding context.

python
from datetime import datetime

CONFIG_DIR = os.path.expanduser("~/.openclaw/x")
CREDS_FILE = os.path.join(CONFIG_DIR, "credentials.json")
OAUTH2_FILE = os.path.join(CONFIG_DIR, "oauth2.json")
TOKENS_FILE = os.path.join(CONFIG_DIR, "tokens.json")
API_BASE = "https://api.x.com/2"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/x.py (reported line 85)May include surrounding context.

python
def refresh_access_token():
    """Refresh OAuth access token using refresh_token."""
    import time
    import base64

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/x.py (reported line 149)May include surrounding context.

python
expires_at = issued_at + expires_in
        
        if time.time() >= expires_at - 60:  # Refresh 60s before expiry
            print("🔄 Access token expired, refreshing...", file=sys.stderr)
            tokens = refresh_access_token()
        
        token = tokens.get("access_token")

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SETUP.md (reported line 22)May include surrounding context.

md
1. **Go to Developer Portal**  
   <https://developer.x.com/en/portal/projects-and-apps>

2. **Create or select an app**  
   - Click "Create App" or select existing
   - Fill in required fields (name, description)

Session Persistence

Medium
Category
Rogue Agent
Confidence
84% confidence
Finding

The OAuth setup instructs users to save a client secret to a local file and later persist OAuth user tokens, including offline access. Persistent long-lived credentials materially increase the blast radius if the host is compromised, especially because the skill supports posting and accessing private account data like bookmarks.

Content

Scanner excerpt · SETUP.md (reported line 93)May include surrounding context.

  1. Save and copy credentials
    After saving, you'll see Client ID and Client Secret.

  2. Create OAuth credentials file

    bash
    cat > ~/.openclaw/x/oauth2.json <<EOF
    

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
97% confidence
Finding

The skill advertises capabilities that perform network access and can write files via shell redirection examples, but it does not declare an explicit tool scope such as permissions or allowed-tools. This creates a governance gap: an agent framework may permit broader execution than intended, increasing the chance of unauthorized outbound requests or local data writes when the skill is invoked.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill supports posting tweets but does not clearly warn that this is a public, externally visible, and effectively irreversible action. In an agent setting, missing confirmation language can lead to accidental posts, reputational harm, disclosure of sensitive information, or unintended actions taken on behalf of the user.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The setup instructions tell users to place a bearer token in ~/.openclaw/x/credentials.json but provide no guidance on file permissions, token sensitivity, rotation, or avoiding accidental disclosure. While storing API credentials locally is common, omitting basic secret-handling warnings in a quickstart can lead to credential leakage through backups, screenshots, shared home directories, or source control mistakes.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · references/quickstart.md (reported line 6)May include surrounding context.

Setup (30 seconds)

bash
# 1. Create credentials file
mkdir -p ~/.openclaw/x
cat > ~/.openclaw/x/credentials.json <<EOF
{

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The quickstart advertises x.py post "Hello world!" alongside read-only commands without any explicit warning that this action publishes content to the user's X account. In an agent skill context, mixing state-changing actions into a terse quick reference increases the risk of unintended public posting, especially if a user or downstream agent treats all examples as safe to run.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SETUP.md (reported line 160)May include surrounding context.

md
CREDS_FILE = os.path.join(CONFIG_DIR, "credentials.json")
OAUTH2_FILE = os.path.join(CONFIG_DIR, "oauth2.json")
TOKENS_FILE = os.path.join(CONFIG_DIR, "tokens.json")
API_BASE = "https://api.x.com/2"

REDIRECT_URI = "http://localhost:8080/callback"
SCOPES = ["tweet.read", "users.read", "bookmark.read", "tweet.write", "offline.access"]

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/pricing.md (reported line 82)May include surrounding context.

md
CREDS_FILE = os.path.join(CONFIG_DIR, "credentials.json")
OAUTH2_FILE = os.path.join(CONFIG_DIR, "oauth2.json")
TOKENS_FILE = os.path.join(CONFIG_DIR, "tokens.json")
API_BASE = "https://api.x.com/2"

REDIRECT_URI = "http://localhost:8080/callback"
SCOPES = ["tweet.read", "users.read", "bookmark.read", "tweet.write", "offline.access"]

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/quickstart.md (reported line 116)May include surrounding context.

md
CREDS_FILE = os.path.join(CONFIG_DIR, "credentials.json")
OAUTH2_FILE = os.path.join(CONFIG_DIR, "oauth2.json")
TOKENS_FILE = os.path.join(CONFIG_DIR, "tokens.json")
API_BASE = "https://api.x.com/2"

REDIRECT_URI = "http://localhost:8080/callback"
SCOPES = ["tweet.read", "users.read", "bookmark.read", "tweet.write", "offline.access"]

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/x.py (reported line 32)May include surrounding context.

python
CREDS_FILE = os.path.join(CONFIG_DIR, "credentials.json")
OAUTH2_FILE = os.path.join(CONFIG_DIR, "oauth2.json")
TOKENS_FILE = os.path.join(CONFIG_DIR, "tokens.json")
API_BASE = "https://api.x.com/2"

REDIRECT_URI = "http://localhost:8080/callback"
SCOPES = ["tweet.read", "users.read", "bookmark.read", "tweet.write", "offline.access"]

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/x.py (reported line 112)May include surrounding context.

python
CREDS_FILE = os.path.join(CONFIG_DIR, "credentials.json")
OAUTH2_FILE = os.path.join(CONFIG_DIR, "oauth2.json")
TOKENS_FILE = os.path.join(CONFIG_DIR, "tokens.json")
API_BASE = "https://api.x.com/2"

REDIRECT_URI = "http://localhost:8080/callback"
SCOPES = ["tweet.read", "users.read", "bookmark.read", "tweet.write", "offline.access"]

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

OAuth access and refresh tokens are persisted to disk in a predictable location without setting restrictive filesystem permissions or warning the user that long-lived credentials will be stored locally. On multi-user systems or where home-directory contents are backed up, synced, or exposed, these tokens could be recovered and used to access the user's X account and private data.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/x.py (reported line 319)May include surrounding context.

python
auth_header = f"Basic {base64.b64encode(credentials).decode()}"
    
    token_req = urllib.request.Request(
        "https://api.twitter.com/2/oauth2/token",
        data=token_body,
        headers={
            "Content-Type": "application/x-www-form-urlencoded",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The bookmarks command retrieves inherently private bookmark data and can print full raw JSON or extracted URLs directly to stdout without any privacy warning, redaction, or confirmation. In agent or shared-shell contexts, this increases the risk of accidental disclosure into logs, transcripts, terminal history capture, or downstream tooling.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.