Back to skill

Security audit

X 长文发布

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent X Articles draft-publishing helper, but it handles live browser login cookies by default and stores them in a local plaintext cache with limited safeguards.

Install only if you are comfortable letting the skill read local X/Twitter browser cookies and create a reusable Playwright login-state file. Treat ~/.cache/x-article-publisher/x-storage-state.json like a password: do not share, commit, sync, or log it, and delete it after use. Prefer manual login or a dedicated browser profile when possible, pin dependencies before use, and review any Markdown from untrusted sources because image URLs can trigger network downloads and matching filenames may be pulled from common personal folders.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/export_x_cookies.py:79
Finding

Plaintext Export and Insecure Storage of Reusable Browser Authentication Cookies

Content
View full analysis
tuple[list[dict], dict[str, int]]: seen: set[tuple[str, str, str, str]] = set() exported: list[dict] = [] counts: dict[str, int] = {} for browser_name in browser_names: browser_count = 0 for domain_name in TARGET_DOMAINS: try: cookie_jar = load_browser_cookies(browser_name, domain_name) except Exception as exc: if browser_count == 0: counts[browser_name] = -1 print( f"[export_x_cookies] Skipping {browser_name} ({domain_name}): {exc}", file=sys.stderr, ) continue for cookie in cookie_jar: if not matches_x_domain(cookie): continue key = (cookie.domain, cookie.path, cookie.name, cookie.value) if key in seen: continue seen.add(key) exported.append(cookie_to_playwright(cookie)) browser_count += 1 counts[browser_name] = browser_count return exported, counts ``` ```python output_path.parent.mkdir(parents=True, exist_ok=True) output_path.write_text(json.dumps(storage_state, ensure_ascii=False, indent=2), encoding="utf-8") print(str(output_path)) print(f"cookies={len(cookies)}") ``` The documented default destination is defined at lines 19-20: ```python DEFAULT_CACHE_ROOT = Path(os.environ.get("XDG_CACHE_HOME", Path.home() / ".cache")) DEFAULT_CACHE_PATH = DEFAULT_CACHE_ROOT / "x-article-publisher" / "x-storage-state.json" ``` ### Technical Analysis The script decrypts or otherwise reads browser cookies thro ...[truncated 2401 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/parse_markdown.py:80
Finding

Unrestricted Remote Image Fetching Enables SSRF-Style Requests and Resource Exhaustion

Content
View full analysis
tuple[str, bool]: if not url.startswith("https://"): print(f"[parse_markdown] WARNING: skipping non-HTTPS image: '{url}'", file=sys.stderr) return url, False REMOTE_IMAGE_DIR.mkdir(parents=True, exist_ok=True) parsed = urllib.parse.urlparse(url) suffix = Path(parsed.path).suffix.lower() if suffix not in {".png", ".jpg", ".jpeg", ".gif", ".webp"}: suffix = "" digest = hashlib.md5(url.encode("utf-8")).hexdigest()[:10] existing = sorted(REMOTE_IMAGE_DIR.glob(f"remote_{digest}.*")) if existing: return str(existing[0]), True try: request = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) with urllib.request.urlopen(request, timeout=30) as response: if not suffix: suffix = extension_from_content_type(response.headers.get_content_type()) output_path = REMOTE_IMAGE_DIR / f"remote_{digest}{suffix}" output_path.write_bytes(response.read()) return str(output_path), True except Exception as exc: print(f"[parse_markdown] WARNING: failed to download '{url}': {exc}", file=sys.stderr) return url, False ``` ### Technical Analysis A remote image URL embedded in Markdown is fetched directly from the environment running the parser. The only destination restriction is that the original string must start with `https://`. That check does not prevent requests to loopback, private, link-local, reserved, or internal network addresses that expose HTTPS. Moreover, `urllib.request.urlopen()` follows redirects by default, and the code does not revalidate the destination after a redirect. An attacker can therefore supply a public HTTPS end ...[truncated 1834 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Mutable and Unpinned Third-Party Dependencies Create Supply-Chain Exposure

Content
View full analysis
=10.0 browser-cookie3>=0.20 ``` `references/cookie-sync.md`: ```bash npx @playwright/mcp@latest \ --storage-state ~/.cache/x-article-publisher/x-storage-state.json ``` The installation instruction in `SKILL.md`, line 44, executes the unpinned Python requirements: ```bash pip install -r skills/x-article-publisher/requirements.txt ``` ### Technical Analysis The Python dependencies use lower bounds without upper bounds, exact versions, or integrity hashes. The package resolver may therefore install versions published after this audit, making the effective codebase non-reproducible. The documented Playwright MCP command explicitly uses the mutable `@latest` npm tag. Running it can download and execute a release that was not present when the skill was reviewed. This exposure is especially significant for `browser-cookie3` because the package is deliberately given access to local browser credential storage. A compromised package release, dependency takeover, or malicious transitive dependency could execute with the user's privileges and access sensitive session material. The reviewed package names are not evident typosquats, and no currently malicious dependency behavior was established from the available source. The confirmed issue is unsafe dependency selection and execution, not proof that the named packages are malicious. ### Attack Path 1. A user follows the documented setup or runtime instructions. 2. `pip` resolves any package version satisfying the lower-bound constraints, or `npx` resolves the current package behind the `latest` tag. 3. A future compromised, malicious, or unexpectedly incompatible release is downloaded. 4. Package installa ...[truncated 1025 chars]
Remediation
View remediation
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The documented behavior claims X/Twitter article publishing, cookie synchronization, and Playwright storage-state handling, while the detected implementation reportedly does not perform those core functions and instead includes unrelated local rendering behaviors. This mismatch is dangerous because operators may trust the skill with sensitive inputs and permissions under false assumptions, masking what the code actually does and weakening review and approval controls.

Content

No source excerpt is available for this finding.

YARA rule 'info_stealer': Information stealer patterns (credential harvesting, browser data theft) [malware]

High
Category
YARA Match
Confidence
97% confidence
Finding

The skill explicitly instructs exporting x.com/twitter.com cookies from local browsers, reusing cached browser session data, and converting them into Playwright storage state for automated login. Browser cookie extraction is highly sensitive because it can enable session hijacking and account takeover if the exported data is exposed, reused outside intended scope, or executed on a host containing another user's authenticated browser profile.

Content

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

publisher/scripts/parse_markdown.py article.md --save-html /tmp/x-article.html --output json python3 skills/x-article-publisher/scripts/copy_to_clipboard.py html --file /tmp/x-article.html

导出或复用 X/Twitter cookies 缓存

python3 skills/x-article-publisher/scripts/export_x_cookies.py

强制刷新缓存,或从其他浏览器读取

python3 skills/x-article-publisher/scripts/export_x_cookies.py --no-cache --browser edge

text

## Default Contract

默认采用以下约定,除非用户另有说明:

- 输入通常是现成 Markdown 文件
- `title`、`cover_image` 等 frontmatter 可以直接作为解析输入
- 目标平台是 X Articles,不是普通 tweet / thread
- 默认只保存草稿,不自动发布
- 默认优先尝试 cookie 同步,再回退到人工登录
- 默认把 storage state 持久化到 `~/.cache/x-article-publisher/x-storage-state.json`
- 默认优先复用有效缓存,而不是每次重新扫描 Chrome cookies
- 如果运行环境没有浏览器�

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill advertises and instructs use of capabilities including local file access, network access, clipboard handling, and browser cookie export, but it does not declare any explicit tool scope or permission boundaries. In an agent setting, this increases the chance that the skill is invoked with broader-than-necessary privileges, enabling unintended access to local data or network resources.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The core instructional content is written in Chinese and does not indicate that the user may choose another language or locale. This creates a natural-language policy issue because the skill effectively enforces a specific language without documented opt-in or justification.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The default prompt instructs the agent to perform multiple sensitive actions automatically, including exporting local X/Twitter cookies into Playwright storage state and driving a browser session. That trigger scope is broad enough to activate credential-handling and automation behavior without explicit user confirmation, increasing the risk of unintended account access or misuse in a high-risk browser-auth context.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
96% confidence
Finding

The documentation instructs users to run npx @playwright/mcp@latest, which pulls and executes the latest package version at runtime rather than a pinned, reviewed release. In a security-sensitive skill centered on exporting and reusing authenticated X/Twitter cookies, this increases supply-chain risk because a compromised or breaking upstream release could gain access to browser automation contexts and storage-state files containing active session tokens.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The troubleshooting guidance instructs operators to export X cookies and reuse them as Playwright storage state, which directly handles live authentication artifacts. Even though this is framed as normal troubleshooting for the skill, the document provides no warning that these files can grant account access and must be protected, increasing the risk of accidental credential exposure, reuse, or insecure transfer.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This section explicitly references a persistent cache file containing auth_token and ct0, which are session credentials, but does not label the cache as sensitive or warn against persistence risks. In a browser automation skill, normalizing long-lived local storage of session tokens without safeguards makes accidental leakage, theft from disk, or unsafe operational practices more likely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This script exports live X/Twitter authentication cookies, including auth_token and ct0, into a plaintext Playwright storage-state JSON on disk without any warning, consent prompt, or protective handling. In the context of a browser automation publishing skill, those cookies are effectively session credentials, so disclosure of the file, reuse by another process, or accidental inclusion in logs/backups can enable account takeover or unauthorized posting.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

When a referenced image is missing, the parser searches common user directories like Downloads, Desktop, and Pictures and substitutes any matching filename it finds. This can cause unintended local file disclosure and publication of unrelated personal images, because attacker-controlled Markdown can reference a generic filename and rely on the fallback search to pick up a sensitive file from the user's machine.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The parser will automatically fetch any HTTPS image referenced in untrusted Markdown, creating undeclared outbound network access during a local parsing step. This can be exploited for SSRF-style requests to internal services, privacy leakage via external beacons, or unexpected downloads of attacker-controlled content, especially because this skill processes existing articles that may come from untrusted or mixed-trust sources.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The visible interface text is presented only in Chinese ('X 长文发布', Chinese short description) with no indication of language choice or opt-in. This can constitute a language/locale policy issue when the skill presentation is fixed to a single language without offering the user an alternative or documenting a justified region-specific constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

All user-facing instructions in this file are in Chinese, and the document does not indicate that the language is optional or region-specific. Per the language/locale policy rule, forcing a specific language without user opt-in can be a natural-language policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

This markdown file documents behavior that fetches remote content and stores it locally, which affects user privacy and the local system state. Under the markdown-specific warning rule, such behavior should be disclosed clearly so users understand that external network requests and temporary file writes will occur.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is specified with a lower bound only, so installs may resolve to different versions over time. This weakens reproducibility and can unintentionally pull in a vulnerable or breaking release, especially in an automation skill that processes untrusted article assets such as images.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
Pillow>=10.0
browser-cookie3>=0.20

Unverifiable Dependency: Pillow has 16 known advisory(ies) (CVE-2016-2533 (Pillow buffer overflow in ImagingPcdDecode); CVE-2023-50447 (Arbitrary Code Execution in Pillow); CVE-2021-27922 (Pillow Uncontrolled Resource Consumption) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding

Pillow has a history of security advisories, and because the manifest does not pin a version, it is impossible to verify whether deployed environments will avoid affected releases. Given this skill's article-publishing context and explicit image handling, a vulnerable Pillow version could expose the system to malicious image parsing issues such as denial of service or, in worst cases, code execution.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
92% confidence
Finding

browser-cookie3 is also unpinned, which means future installations may fetch different releases with unknown security properties. In this skill, the package handles browser cookie extraction, so dependency drift is somewhat more sensitive because it interacts with authentication material.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
Pillow>=10.0
browser-cookie3>=0.20

Static analysis

No suspicious patterns detected.