Back to skill

Security audit

X Post Strategist

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly matches its X-post drafting purpose, but its optional image renderer opens local HTML in Chrome without blocking scripts or network access, so it needs review before installation.

Install only if you are comfortable with an optional Puppeteer/Chromium renderer and local draft-saving. Use the renderer only on trusted, self-contained HTML, avoid untrusted HTML or copied active markup, review OBSIDIAN_VAULT_PATH and Chrome-related environment variables, and consider blocking network/JavaScript or updating dependencies before rendering cards.

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

Warning
Location
scripts/render-image.js:130
Finding
Unrestricted Network Access and Script Execution During HTML Rendering## Vulnerability Details **File Location**: `scripts/render-image.js`, lines 130–136 **Vulnerability Type**: Untrusted active HTML rendered without JavaScript or network isolation **Risk Level**: Medium **Complete Code Snippet**: ```js const page = await browser.newPage(); await page.setViewport({ width: opts.width, height: opts.height, deviceScaleFactor: opts.scale, }); await page.goto("file://" + path.resolve(inputPath), { waitUntil: "networkidle0" }); await page.screenshot({ path: outputPath, fullPage: opts.full }); process.stdout.write(`OK\t${path.resolve(outputPath)}\t${opts.width}x${opts.height}@${opts.scale}x\n`); ``` ### Technical Analysis The renderer accepts an arbitrary local HTML path and opens it in a JavaScript-enabled Chromium page. It does not disable JavaScript, intercept browser requests, restrict URL schemes, or block external and private-network destinations. Project documentation instructs authors to create self-contained HTML without external assets, but the implementation does not enforce that requirement. Therefore, crafted HTML can contain active elements such as `<script>`, `<iframe>`, or resource references that cause Chromium to initiate network requests. For example, a malicious input document could execute JavaScript that sends a request to an attacker-controlled endpoint or attempts blind interaction with services reachable from the rendering host. The browser sandbox limits direct host access, but it does not provide network isolation. ### Attack Path 1. An attacker supplies crafted content, or attacker-controlled text is inserted into an HTML card without correct contextual escaping. 2. The resulting document contains executable JavaScript, active markup, or remote resource references. 3. A user or agent invokes: ```sh node scripts/render-image.js malicious.html output.png ``` 4. The script opens the document through `page.goto()` in a JavaScript-enabled ...[truncated 1277 chars]
Remediation
## Remediation Suggestions 1. Disable JavaScript for static text and data cards before navigation: ```js await page.setJavaScriptEnabled(false); ``` 2. Enable request interception and deny network access by default. Permit only the initial local document and explicitly approved local resources: ```js await page.setRequestInterception(true); page.on("request", (request) => { const url = new URL(request.url()); if (url.protocol === "file:") { request.continue(); } else { request.abort(); } }); ``` 3. If network access is ever required, use a strict allowlist. Explicitly block: - Loopback addresses. - Private IPv4 and IPv6 ranges. - Link-local and cloud metadata endpoints. - Redirects to non-allowlisted destinations. - Unnecessary schemes such as `http:`, `https:`, `ftp:`, and `ws:`. 4. Escape all user-derived values according to their HTML context. Do not insert untrusted text through raw HTML concatenation or `innerHTML`. 5. Validate generated documents and reject active content, including: - `<script>` - `<iframe>` - `<object>` - `<embed>` - Event-handler attributes such as `onload` and `onclick` - JavaScript URLs - External stylesheets, fonts, images, and media 6. Consider rendering from a trusted fixed template with text passed through a structured data interface instead of accepting arbitrary HTML files. 7. Run Chromium in a network-restricted container or sandbox as defense in depth, while retaining the browser's operating-system sandbox. 8. Add automated tests proving that JavaScript execution and outbound, loopback, private-network, and metadata-service requests are blocked.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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
Findings (25)

Credential Access

High
Category
Privilege Escalation
Content
- Feedback prompt in README.md and conditional feedback section in SKILL.md

## [0.5.3] - 2026-05-20
- Fix `getCredentials()` in `save_to_sheet.js`: load `client_id`/`client_secret` from `credentials.json` before token cache check so token refresh works correctly
- Add `normalizeToken()` to handle Python-client token format (`token` → `access_token`, `expiry` → `expiry_date`) so tokens created by other Google OAuth clients are reused without re-auth

## [0.5.2] - 2026-05-20
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The manifest presents the skill as a writing utility, but the body adds local file rendering, browser launch, and image generation workflows. This mismatch is dangerous because operators may approve or invoke the skill under the assumption it only rewrites text, while it actually expands into local execution and file I/O surfaces.

Ae1

High
Category
analysis-evasion
Content
node scripts/render-image.js <input.html> <output.png> [--width=1080] [--height=1080] [--scale=2]
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
node scripts/render-image.js <input.html> <output.png> [--width=1080] [--height=1080] [--scale=2]
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Known Vulnerable Dependency: extract-zip==2.0.1 — 2 advisory(ies): CVE-2026-19693 (extract-zip allows arbitrary file writes through symlink archive entries); CVE-2026-56876 (extract-zip unvalidated symlink path traversal)

High
Category
Supply Chain
Confidence
93% confidence
Finding
extract-zip 2.0.1 is a real supply-chain risk because known symlink handling flaws can let a crafted archive write files outside the intended extraction directory. In this lockfile it is pulled in transitively by Puppeteer's browser-management stack, so the danger depends on whether the skill ever processes attacker-controlled ZIP content or browser downloads; if it does, this can become arbitrary file overwrite with possible code execution follow-on.

Known Vulnerable Dependency: ip-address==10.2.0 — 3 advisory(ies): CVE-2026-54272 (ip-address: misclassification of IPv4-mapped/NAT64 IPv6 addresses can bypass SSR); CVE-2026-69198 (ip-address: a CIDR suffix on the parsed address suppresses special-use classific); CVE-2026-69192 (ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco)

High
Category
Supply Chain
Confidence
84% confidence
Finding
ip-address 10.2.0 has reported parsing and classification flaws that can misidentify special-use or mapped addresses, which can undermine SSRF protections or network allow/deny logic. In this package-lock it is only a transitive dependency of proxy-related libraries used by Puppeteer, so the issue is context-dependent and becomes dangerous mainly if the skill relies on this stack to enforce network restrictions, proxy policy, or localhost blocking.

Known Vulnerable Dependency: js-yaml==4.2.0 — 3 advisory(ies): CVE-2026-84375 (js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources); CVE-2026-59869 (js-yaml: YAML merge-key chains can force quadratic CPU consumption); GHSA-5p4m-2wfm-xmqj (JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) — CVE-2026)

High
Category
Supply Chain
Confidence
80% confidence
Finding
js-yaml 4.2.0 has known denial-of-service issues where crafted YAML with merge-key or omap structures can trigger excessive CPU consumption during parsing. Here it appears as a transitive dependency via cosmiconfig in the Puppeteer toolchain, so exploitability depends on whether this skill loads attacker-controlled YAML/config files; if so, an attacker could cause hangs or resource exhaustion rather than direct code execution.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill uses environment-derived behavior (`OBSIDIAN_VAULT_PATH`) but declares no explicit tool or permission scope. That creates hidden capability expansion: a drafting skill can access runtime configuration and influence filesystem write targets without the manifest clearly constraining or disclosing it.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The skill requires web/X research and trend scanning even though its declared purpose is transforming user-provided material into posts. This broadens data flow and external interaction, increasing risk of unintended transmission of sensitive source text and introducing prompt-injection or misinformation from external content into the drafting process.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- Use a single post when the idea has one clear point, one timely observation, or one concise takeaway.
- Use a thread when the source material has multiple claims, a process, a technical explanation, a story arc, or several useful examples.
- For non-Premium accounts, each post must be ≤ **280 characters** (spaces and punctuation included). If the user confirmed "single post", compress the content to fit — cut, distil, and sharpen until it fits. Do not ask the user to switch to a thread.
- For Premium accounts, posts may be up to **25,000 characters**. "Tight" means no filler — not necessarily short. Match length to the material: when the source is a long, rich, or structured document (a research report, deep-dive, or spec), default to a fuller, denser treatment that actually uses the material — do not reflexively compress it into a short post. Still cut every word that does not earn its place.

**Thread narrative templates** — select one based on content type and name it in the output:
Confidence
80% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The skill includes persistent vault-writing behavior unrelated to its core drafting function. Any file-write capability increases the blast radius from text generation to local data modification, and persistence can be abused to place unwanted content into a user's notes or overwrite trusted organizational structures.

Intent-Code Divergence

Medium
Confidence
86% confidence
Finding
The instructions claim saving is opt-in, but elsewhere require running the save workflow after every draft. This contradiction is risky because ambiguous consent handling often leads to unintended persistence, especially when combined with auto-save behavior for the rest of the session.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- Always run all three sub-tasks in Step 2 before drafting — even for long, detailed input.
- If goal, audience, and tone are all unspecified, select the 3 best style combinations from the source material, draft and score all three, then present them for the user to choose from (short Non-Premium single posts only; for long-form output produce one draft and offer angles conversationally — see Step 7).
- For long-form output — a thread (any account) or a Premium single post — default to one draft whose depth matches the material; never reflexively produce a short post or multiple parallel variants. After drafting, offer other angles for the user to opt into and/or propose specific improvements, and revise iteratively until the user is satisfied. Parallel multi-variant drafting is reserved for short Non-Premium single posts.
- Non-Premium single posts must not exceed 280 characters. Compress to fit — do not ask the user to switch to a thread.
- Keep the final text publishable, not just instructive.
- Do not make weak material sound more certain than it is.
- Do not recommend images automatically.
Confidence
80% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The document instructs users how to write posts specifically as Chinese AI / tech X posts and consistently frames the desired output as a short Chinese post. There is no indication that the language preference is optional or user-selected, which can violate a language/locale policy requiring choice or opt-in.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The file documents image-generation and headless-browser rendering capabilities that are broader than the skill's declared purpose of generating X post copy. Even though the document warns against credentials and network use, adding rendering workflows and browser-based execution expands the operational scope and attack surface of the skill, creating opportunities for misuse, unsafe file handling, or unintended execution paths not justified by the manifest.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
This documentation introduces headless Chrome execution for turning HTML/CSS into PNGs, which is a materially more powerful capability than text-only X post drafting. Headless browser execution can process untrusted HTML, invoke local browser features, and encourage a workflow that may later be applied to attacker-controlled content, making the skill more dangerous in context because the manifest does not prepare users or reviewers for browser automation behavior.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
This script adds HTML-to-image rendering via a headless browser, which materially exceeds the stated scope of a skill meant only to generate X post/thread text. Extra execution capability increases attack surface because rendering arbitrary HTML can trigger local file rendering and network-fetch behavior inside Chromium, enabling unintended data access or exfiltration paths if untrusted HTML is processed.

Intent-Code Divergence

Medium
Confidence
90% confidence
Finding
The docstring states that no network access is required, but page.goto(..., { waitUntil: 'networkidle0' }) will permit and wait on network activity during page load if the HTML references remote resources. This mismatch is dangerous because it can mislead reviewers and operators into treating the component as offline-only when it may actually fetch external content or leak data.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
Launching Puppeteer/Chrome to open attacker-influenced HTML introduces a powerful execution surface that is not justified by the skill's text-only purpose. A headless browser may load remote resources, access local file content referenced by the HTML, and process active web content, making this significantly more dangerous than ordinary text generation.

Natural-Language Policy Violations

Low
Confidence
94% confidence
Finding
The README states that the skill 'defaults to English unless another language is requested,' which imposes a language preference before the user has explicitly opted in. The policy for natural-language violations says locale or language should not be forced unless the skill offers a choice or the constraint is clearly justified.

Context-Inappropriate Capability

Low
Confidence
88% confidence
Finding
Reading `OBSIDIAN_VAULT_PATH` adds hidden configuration dependence to a skill that is ostensibly for drafting posts. Even if low severity by itself, environment-variable-driven path selection can redirect saved content to unexpected locations and bypass clearer user approval flows.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The document declares `lang="en"`, which is a natural-language locale choice embedded in the file. Under the stated policy, forcing a specific language without user opt-in can be a locale policy violation, and this file provides no indication that English is optional or required for a justified region-specific purpose.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
The document explicitly sets `lang="en"`, which hard-codes English as the template's language/locale. Under the policy criteria, forcing a specific language without user opt-in or a documented region-specific justification is a natural-language policy concern.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"node": ">=18"
  },
  "dependencies": {
    "puppeteer": "^24.15.0"
  }
}
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Context-Inappropriate Capability

Low
Confidence
79% confidence
Finding
The script reads PUPPETEER_EXECUTABLE_PATH and RENDER_CHROME_ARGS to influence browser execution. Accessing environment-based execution configuration is not an obvious requirement for a skill intended only to compose X posts from source material.

Static analysis

No suspicious patterns detected.