Back to skill

Security audit

⁠X Reader⁠

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a disclosed X/Twitter reader, but its article path can open and extract content from non-X URLs crafted to look like X article links.

Review before installing. Use it only with links you trust, preferably with a secondary X account, because it consumes local X session cookies. The main issue to fix before broad use is strict URL validation for article mode so Playwright can only load approved X/Twitter hosts and cannot be pointed at local or private-network pages.

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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/xreader.mjs:446
Finding

Unrestricted URL Handling Enables Server-Side Request Forgery and Local Content Extraction

Content
View full analysis
{}); await page.waitForTimeout(1500); ``` ```js async function main() { const { mode, debug, thread, url } = parseArgs(process.argv.slice(2)); const auth = loadAuth(); if (!auth) { console.log(JSON.stringify({ ok: false, error: 'auth_missing', message: `Missing auth file. Expected ${NEW_AUTH_PATH} (legacy fallback: ${LEGACY_AUTH_PATH}).`, }, null, 2)); process.exit(2); } let canonicalUrl = url; let resolvedToArticle = false; if (/^https?:\/\/t\.co\//i.test(url)) { canonicalUrl = await resolveUrl(url); resolvedToArticle = /x\.com\/i\/article\//i.test(canonicalUrl); } if (/x\.com\/i\/article\//i.test(canonicalUrl)) { const article = await extractArticleWithPlaywright(canonicalUrl, auth, mode, debug); console.log(JSON.stringify(article, null, 2)); return; } ``` ```js const tweetText = tweet.full_text || tweet.text || ''; if (/^https?:\/\/t\.co\//i.test(tweetText.trim())) { try { const maybe = await resolveUrl(tweetText.trim()); if (/x\.com\/i\/article\//i.test(maybe)) articleUrl = maybe; } catch {} } ``` ### Technical Analysis The Skill determines whether a URL represents an X article by applying the substring regular expression `/x\.com\/i\/article\//i` to the complete URL. It does not parse the URL and verify that its hostname is exactly an approved X domain. Consequently, an attacker-controlled URL such as: ```text http://127.0.0.1/x.com/i/ ...[truncated 3008 chars]
Remediation
View remediation
{ const requestUrl = new URL(route.request().url()); const allowedHosts = new Set(['x.com', 'www.x.com', 'abs.twimg.com', 'pbs.twimg.com']); if (requestUrl.protocol ! ...[truncated 595 chars]
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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- Confirm `SKILL.md` includes usage, dependencies, auth path, and limitations.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill clearly instructs the agent to access external X/Twitter URLs, resolve t.co redirects, and use Playwright/xreach, which implies network-capable execution. However, the manifest does not declare any explicit tool scope such as permissions or allowed-tools, so the skill's operational capabilities are under-specified. This weakens least-privilege enforcement and can cause the skill to run with broader network access than reviewers or policy systems expect.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script reads persistent X session tokens from files in the user's home directory and automatically migrates them to a new location. For a link-reader skill, silently accessing and reusing account credentials expands privilege beyond simple public-content fetching and creates account-token exposure risk if the skill, its outputs, or downstream components are compromised.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script loads sensitive auth_token and ct0 values from local session files and later uses them for authenticated browser access without any user-facing notice or consent. This is dangerous because it silently leverages an existing logged-in X session, potentially exposing private account capabilities and making users unaware that local credentials are being consumed by the skill.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest presents the skill as a reader/summarizer for X links and mentions preferring xreach, but it does not disclose that the implementation executes a local binary via child_process. Launching subprocesses is a broader capability than ordinary URL reading and introduces behavior not clearly justified by the stated purpose alone.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
91% confidence
Finding

The dependency uses a caret range (^1.53.0), which allows automatic installation of newer compatible versions instead of a single audited release. That increases supply-chain risk because builds may silently change over time and could pick up a compromised or breaking package version without explicit review.

Content

Scanner excerpt · package.json (reported line 6)May include surrounding context.

json
"private": true,
  "type": "module",
  "dependencies": {
    "playwright": "^1.53.0"
  }
}

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
75% confidence
Finding

resolveUrl issues HTTP GET requests to user-supplied URLs, disclosing the user's IP address and a custom user-agent to remote servers. The script contains no warning in help text or inline disclosure that URL resolution and later page loading will contact external sites.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The Playwright context is hard-coded with locale: 'en-US', which imposes a specific locale setting regardless of user preference. This matches the language/locale policy concern because the file does not offer opt-in, configuration, or explanation for the forced locale.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/xreader.mjs:54