Back to skill

Security audit

X Auto-Tweet (Browser)

Security checks for vulnerabilities and agentic risk

Overview

This skill is openly built to control a logged-in X account, but its live posting, optional automation, persistent session use, and privacy claims need careful review before installation.

Install only if you are comfortable letting this skill control a logged-in X browser session and potentially publish public posts from your account. Keep human approval mandatory for every post, avoid the whitelist/full-auto modes, use an isolated browser profile if possible, review local data files regularly, and pin dependencies before relying on it.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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)

T01 · Skill Instruction Hijacking

Warning
Location
scripts/auto-tweet.js:26
Finding
Untrusted X Trend Content Is Passed into the Agent Content-Generation Flow<![CDATA[ ## Vulnerability Details **File Location**: `scripts/auto-tweet.js:26-36`, `scripts/auto-tweet.js:62-65`, `scripts/trends.js:25-36`, `scripts/generate-ideas.js:20-25`, and `scripts/generate-ideas.js:38-42` **Vulnerability Type**: Indirect prompt injection through untrusted external content **Risk Level**: Medium ### Vulnerable Code `scripts/auto-tweet.js:26-36`: ```js const trends = await page.evaluate(() => { const trendElements = document.querySelectorAll('[data-testid="trend"]'); return Array.from(trendElements).slice(0, 10).map(el => { const nameEl = el.querySelector('[dir="ltr"]'); const tweetCountEl = el.querySelector('span:last-child'); return { topic: nameEl ? nameEl.textContent : 'Unknown', tweets: tweetCountEl ? tweetCountEl.textContent : '0' }; }); }); ``` `scripts/auto-tweet.js:62-65`: ```js fs.writeFileSync(trendsFile, JSON.stringify({ timestamp: new Date().toISOString(), trends }, null, 2)); ``` `scripts/trends.js:25-36`: ```js const trends = await page.evaluate(() => { const trendElements = document.querySelectorAll('[data-testid="trend"]'); return Array.from(trendElements).slice(0, 10).map(el => { const nameEl = el.querySelector('[dir="ltr"]'); const tweetCountEl = el.querySelector('span:last-child'); return { topic: nameEl ? nameEl.textContent : 'Unknown', tweets: tweetCountEl ? tweetCountEl.textContent : '0', timestamp: new Date().toISOString() }; }); }); ``` `scripts/generate-ideas.js:20-25`: ```js const data = JSON.parse(fs.readFileSync(trendsFile, 'utf8')); const trends = data.trends; console.log('🔥 Top 5 Trending Topics:'); console.log('========================\n'); trends.slice(0, 5).forEach((trend, i) => { ``` `scripts/generate-ideas.js:38-42`: ```js // Return trends as JSON for agent to process console.log('\n---TRENDS_JSON---'); console.log(JSON.stringify(trends.slice(0, 5), null, 2)); console.log('---END_TRENDS_JSON---'); ``` ...[truncated 2478 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat all scraped website values as untrusted data and state this explicitly in every agent prompt that consumes them. 2. Require the agent to ignore commands, policy statements, tool requests, encoded payloads, and role-like instructions found inside trend fields. 3. Pass trends through a structured tool interface with a strict schema instead of incorporating console output directly into an instruction prompt. 4. Validate each field before storage and processing: - Enforce conservative maximum lengths. - Remove control characters and bidirectional text controls. - Reject unexpected multiline values. - Accept only the fields needed for topic analysis. 5. Keep data and instructions in separate prompt sections. For example, state that quoted trend fields are evidence to summarize and can never modify the task. 6. Use a dedicated low-privilege generation step that has no browser-posting or sensitive-context access. 7. Preserve a mandatory, explicit human approval boundary before every post. Approval should display the exact final text that will be submitted. 8. Record the source and processing history of each generated tweet so suspicious trend inputs can be traced. ]]>

T08 · Insecure Dependencies

Note
Location
package.json:13
Finding
Dependency Installation Is Not Reproducibly Pinned<![CDATA[ ## Vulnerability Details **File Location**: `package.json:13-15`, `SKILL.md:48-51`, and `QUICKSTART.md:9-13` **Vulnerability Type**: Mutable third-party dependency resolution **Risk Level**: Low ### Vulnerable Code `package.json:13-15`: ```json "dependencies": { "playwright": "^1.40.0" } ``` `SKILL.md:48-51`: ```bash cd ~/.openclaw/workspace/skills/x-automation npm install ``` `QUICKSTART.md:9-13`: ```bash cd ~/.openclaw/workspace/x-automation npm install ``` ### Technical Analysis The project declares Playwright with a caret range and does not include a reviewed lockfile in the supplied project. The command `npm install` can therefore resolve different dependency and transitive-dependency versions at different times. This does not demonstrate that the current Playwright package is malicious. The weakness is that the installed dependency graph is mutable and not reproducible from the audited source alone. If a future version satisfying the range, a transitive package, or the relevant registry distribution channel were compromised, installation could retrieve and execute code that was not part of this review. The risk is particularly relevant because Playwright is subsequently attached to an existing authenticated browser context through the local Chrome DevTools Protocol endpoint. ### Attack Path 1. A user follows the documentation and runs `npm install`. 2. npm resolves the caret range and transitive dependency graph at installation time. 3. A future compromised or unexpectedly modified version satisfying the declared range is selected. 4. Package installation behavior or runtime code executes on the user's machine. 5. When the automation scripts run, compromised dependency code operates with the Node.js process privileges and may interact with the authenticated browser connection. 6. Within those existing privileges, malicious dependency code could access local files readable by the process, alter automation behavior, or misuse browser ...[truncated 735 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin Playwright to a reviewed exact version rather than a caret range. 2. Generate and commit a `package-lock.json` containing the complete reviewed dependency graph. 3. Replace documented `npm install` instructions with `npm ci` so installation fails if the manifest and lockfile disagree. 4. Review package lifecycle scripts and the complete transitive dependency tree before release. 5. Use automated dependency scanning and integrity monitoring for both direct and transitive dependencies. 6. Apply dependency updates through controlled review requests, with lockfile diffs inspected before merging. 7. Avoid running npm or the automation scripts with elevated operating-system privileges. 8. Where operationally feasible, disable unnecessary lifecycle scripts during installation and install inside an isolated environment with access limited to the required browser endpoint and project data. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (15)

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The quick-start flow tells the user to run a posting command immediately after setup, but it does not clearly warn that the command will publish a live post to the user's X account. In a browser-session automation context, this can cause unintended public actions from the user's authenticated account, creating reputational and operational risk.

Session Persistence

Medium
Category
Rogue Agent
Content
- [ ] Test trend scraping
- [ ] Test posting
- [ ] Build auto-tweet flow
- [ ] Add cron job for automation
- [ ] Monitor mentions
- [ ] Strategic liking/RTing
Confidence
81% confidence
Finding
The documented next step to add a cron job for automation encourages unattended operation tied to the user's persistent browser session. In this skill's context of bypassing the official API and acting through a logged-in browser, scheduled automation increases the chance of unauthorized or unexpected posting, account misuse, and session exposure if the host is compromised.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The README explicitly instructs the skill to attach to a logged-in X browser session and automate scraping, posting, and monitoring actions on the user's account without clearly disclosing the privacy, account-security, and platform-enforcement risks. Because the automation operates with the user's live authenticated session, misuse or unexpected behavior could expose private account data, perform unwanted actions, or lead to suspension while appearing as legitimate user activity.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The cron example encourages unattended recurring access to the user's authenticated X session and instructs the system to generate tweet ideas and send them to Telegram, but it does not clearly warn that this creates ongoing account access and external data transfer. In context, scheduled automation increases risk because it can repeatedly scrape account-related information or leak generated/account-derived content to third-party messaging services without continuous user awareness.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The cron workflow enables unattended recurring actions on the user's X account but does not prominently warn that the automation can repeatedly scrape, generate, and potentially lead to posting activity without immediate user review. In the context of a social-media automation skill, missing warnings increase the risk of accidental account misuse, spammy behavior, or platform enforcement against the user's account.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
## Safety Features

- **No auto-posting without approval** (unless you configure it)
- **Human-like delays** (30-60s between tweets)
- **Daily limits** (configurable, default 10/day)
- **Queue review** before posting
Confidence
90% confidence
Finding
The phrase 'No auto-posting without approval (unless you configure it)' confirms the skill supports disabling approval and allowing autonomous posting decisions. In this context, the skill can generate and publish content to a real user account, making unsupervised operation risky because errors, prompt injection from scraped content, or bad model outputs could directly cause reputational harm or account sanctions.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The document claims the skill is 'credential-free' and involves 'no private data,' but the skill depends on a persisted authenticated X browser session tied to the user's account. That session is effectively an authentication credential, and the skill also stores account-derived activity data locally, so the claim can mislead users into underestimating account and privacy risk.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The documentation describes scraping X trends and sending generated content to Telegram, but it does not disclose what data may be collected, stored, transmitted, or retained across those systems. This creates privacy and compliance risk because user interests, account-related activity, trend data, approval decisions, and message contents may be processed or stored without clear notice, minimization, or retention controls.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The workflow documents broad natural-language commands like asking to check trends, generate tweet ideas, post tweets, and show history without requiring an explicit confirmation or tightly scoped command format. In an agent setting, ambiguous trigger phrases can cause unintended invocation or action execution from casual conversation, forwarded text, or prompt injection embedded in surrounding context.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
## ⚠️ Safety Features

- **No auto-posting without approval** (except if you whitelist it)
- **Daily tweet limit:** Max 10 tweets/day (avoid spam)
- **Human-like delays:** 30-60 sec between tweets
- **Content review:** All tweets shown to you first
Confidence
76% confidence
Finding
Although framed as a safety feature, the phrase 'except if you whitelist it' introduces a pathway to autonomous posting with reduced human oversight. In a system that generates content from scraped trends and operates on a schedule, allowing autonomous exceptions can lead to unintended, reputationally damaging, or policy-violating posts if approvals are bypassed or the whitelist is too broad.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The final call-to-action invites the user to say a generic phrase to start the workflow, which reinforces ambiguous NL-based triggering with no scope or authorization boundary. In a conversational agent, this increases the chance that unrelated text, quoted content, or social-engineered prompts trigger scraping or tweet-generation behavior unexpectedly.

Missing User Warnings

Low
Confidence
86% confidence
Finding
The skill describes scraping and generation features without clearly warning users that trends, approved queue items, and tweet history are persisted to local JSON files. This creates a transparency and privacy issue because users may not realize their account-related activity and generated content are being stored on disk.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"auto": "node scripts/auto-tweet.js"
  },
  "dependencies": {
    "playwright": "^1.40.0"
  },
  "author": "",
  "license": "MIT"
Confidence
95% confidence
Finding
The dependency is specified with a caret range (^1.40.0), which allows newer minor versions to be installed and makes builds non-reproducible. In an automation skill that drives a browser, dependency drift can unexpectedly pull in vulnerable or behavior-changing releases, increasing supply-chain risk.

Unverifiable Dependency: playwright has 1 known advisory(ies) (CVE-2025-59288 (Playwright downloads and installs browsers without verifying the authenticity of)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
80% confidence
Finding
The manifest references Playwright without exact pinning, while the package has a known advisory related to downloading/installing browsers without authenticity verification. Because the resolved version is not fixed, deployments may install an affected release, which is more concerning here because this skill explicitly relies on browser automation and therefore may trigger browser download/install flows.

Intent-Code Divergence

Low
Confidence
93% confidence
Finding
The header comment describes the script as 'Scrape trending topics from X', which suggests data retrieval behavior only. The implementation additionally creates a local data directory and writes the results to a timestamped JSON file at L44-L51, introducing a side effect not reflected in the documentation.

Static analysis

No suspicious patterns detected.