Back to skill

Security audit

X

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent X API client, but it deserves review because it stores long-lived X credentials locally and can publish posts from the user's account without strong safeguards.

Review before installing if this will run on a shared machine or with an account where accidental posts matter. Use a dedicated/test X app and account where possible, restrict ~/.openclaw/x to owner-only permissions, rotate tokens if exposed, set X spending limits, and require explicit user approval before any post command is run.

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:69
Finding

Credential and OAuth Token Files Are Created Without Enforced Restrictive Permissions

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

T09 · Insecure Skill Coding Practices

Note
Location
scripts/x.py:263
Finding

OAuth Callback Uses a Constant State and Does Not Validate Response Correlation

Content
View full analysis
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 (24)

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

The guide instructs users to place bearer credentials in a plaintext JSON file under the home directory without mentioning restrictive file permissions or OS secret storage. If that file is readable by other local users, backup systems, or other tools, the token could be stolen and abused to access API data or incur charges.

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
89% confidence
Finding

The file structure section confirms that bearer tokens, OAuth client secrets, and user tokens are stored in predictable plaintext locations. That predictability makes accidental disclosure and opportunistic local credential harvesting easier if the host is shared or 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
94% confidence
Finding

The documentation explicitly directs creation of a credentials file containing a bearer token, which is sensitive authentication material. If that file is readable by other users, included in backups, or committed to source control, an attacker could use the token to access X API resources and act within the associated application's privileges.

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
79% confidence
Finding

The script stores credentials and OAuth tokens under a predictable path in the user's home directory but does not set restrictive filesystem permissions when writing sensitive token material. On multi-user or misconfigured systems, these files could be read by other local users or processes, exposing bearer, access, or refresh tokens.

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 · SETUP.md (reported line 199)May include surrounding context.

md
if os.path.exists(OAUTH2_FILE):
        with open(OAUTH2_FILE) as f:
            return json.load(f)
    # Try legacy credentials.json format
    creds = load_creds()
    if "client_id" in creds:
        return creds

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
if os.path.exists(OAUTH2_FILE):
        with open(OAUTH2_FILE) as f:
            return json.load(f)
    # Try legacy credentials.json format
    creds = load_creds()
    if "client_id" in creds:
        return creds

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
86% confidence
Finding

The OAuth setup instructs users to save client ID and client secret in a plaintext file, creating long-lived local persistence of sensitive authentication material. In this skill context, that increases the blast radius of local compromise because the stored OAuth secrets can be used to mint or support access tied to X account operations.

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
    

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The setup guide instructs users to post a tweet as a test but does not explicitly warn that this is a public write action performed on the user's real X account. In an agent skill context, omitting that caution increases the chance of unintended public posting, reputational harm, or accidental disclosure if users treat the command as a harmless connectivity check.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill advertises capabilities that can perform network access and write data to files, but it does not declare any explicit tool scope such as permissions or allowed-tools. This weakens least-privilege controls and makes it easier for an agent runtime to invoke broader capabilities than reviewers or users expect.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill includes a command to post tweets but does not clearly warn that this is a live write action affecting the user's X account. Without an explicit destructive-action warning and confirmation requirement, an agent or user could trigger public posting unintentionally, causing reputational or operational harm.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
86% confidence
Finding

Persisting authentication material in a long-lived local file increases the attack surface because the secret remains available across sessions and may be recovered later by malware, other local users, or forensic collection. In this skill's context, persistent API credentials enable repeated access to external account data and services without additional user 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
95% confidence
Finding

The quickstart instructs users to store a bearer token in a local credentials file but provides no guidance on file permissions, secret handling, or avoiding accidental disclosure through backups, repos, or shared systems. In a skill that accesses a live external account, exposed bearer tokens can enable unauthorized API access and data retrieval under the user's identity or app context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The OAuth examples include a posting command that performs a state-changing action on an external service without any warning that it will publish content publicly or to a real account. In an agent/tooling context, this raises the risk of accidental posting, reputational harm, or unintended automation against a user's social media account.

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"]

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",

Static analysis

No suspicious patterns detected.