Back to skill

Security audit

Wip Xai X Private

Security checks for vulnerabilities and agentic risk

Overview

This X/Twitter automation skill mostly matches its stated purpose, but it needs Review because it combines write-capable account credentials with unsafe local file upload handling and an unsafe 1Password shell call.

Install only if you are comfortable granting an agent X account credentials that can post, delete, bookmark, and upload media. Prefer a read-only bearer token unless write access is truly needed, run it with minimal filesystem access, do not expose sensitive directories to the MCP process, and avoid using the 1Password auto-lookup path until the shell invocation is hardened.

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

Error
Location
'); process.exit(1); } const result = await upload_media({ file_path: file }); ``` ### Technical Analysis The media upload function accepts an arbitrary filesystem path and passes it directly to `readFileSync`. It does not: - Restrict access to a designated media directory. - Canonicalize the supplied path before enforcing a boundary. - Reject absolute paths or traversal sequences. - Reject symbolic links. - Verify that the target is a regular file. - Validate the actual file signature against the decl ...[truncated 2294 chars]:211
Finding
Arbitrary Local File Disclosure Through Media Upload<![CDATA[ ## Vulnerability Details **File Location**: `core.mjs:211-218, 229-233`; `mcp-server.mjs:105-113, 150-151`; `cli.mjs:134-137, 174-177` **Vulnerability Type**: Unrestricted local file read and network transmission **Risk Level**: High ### Vulnerable Code `core.mjs:211-218, 229-233`: ```javascript export async function upload_media({ file_path, media_data, media_type, alt_text } = {}) { if (!file_path && !media_data) throw new Error('file_path or media_data is required'); const client = await getClient(); let data = media_data; if (file_path && !data) { const buffer = readFileSync(file_path); data = buffer.toString('base64'); } // Detect media type from extension if not provided if (!media_type && file_path) { const ext = file_path.split('.').pop().toLowerCase(); const types = { png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif', mp4: 'video/mp4', webp: 'image/webp' }; media_type = types[ext] || 'application/octet-stream'; } const body = { mediaData: data, mediaType: media_type, }; const result = await client.media.upload({ body }); ``` `mcp-server.mjs:105-113, 150-151`: ```javascript { name: 'x_upload_media', description: 'Upload media (image/video/gif) for use in tweets. Returns a media ID.', inputSchema: { type: 'object', properties: { file_path: { type: 'string', description: 'Path to the file to upload' }, media_type: { type: 'string', description: 'MIME type (auto-detected from extension if omitted)' }, }, required: ['file_path'], }, }, ``` ```javascript case 'x_upload_media': result = await upload_media(params); break; ``` `cli.mjs:134-137, 174-177`: ```javascript if (mediaFile) { const upload = await upload_media({ file_path: mediaFile }); if (upload.data?.id) mediaIds = [upload.data.id]; } ``` ```javascript case 'upload': { const file = args[1]; if (!file) { console.error('Usage: wip-x upload <file>'); process.ex ...[truncated 2684 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Use an explicit upload root** - Require an administrator-configured media directory. - Resolve both the upload root and requested file with `realpath`. - Verify that the resolved file remains strictly inside the approved root. 2. **Harden filesystem validation** - Reject absolute paths unless explicitly permitted. - Reject traversal outside the approved root. - Use `lstat` and `stat` to reject symbolic links and non-regular files. - Open files with protections against symlink races where supported. - Apply a conservative maximum file size before reading the content. 3. **Validate actual content** - Permit only documented image and video formats. - Check file magic bytes rather than trusting the extension or caller-provided MIME type. - Reject `application/octet-stream` instead of uploading unknown file types. 4. **Reduce Agent privileges** - Prefer opaque attachment handles or bytes supplied by a trusted host instead of arbitrary paths. - Require explicit user confirmation showing the canonical path, size, type, and destination before an MCP upload. - Run the MCP process with minimal filesystem permissions. 5. **Improve implementation behavior** - Stream supported uploads where possible rather than reading the entire file synchronously. - Log upload authorization decisions without logging file contents or credentials. - Add tests covering absolute paths, `../` traversal, symlinks, oversized files, and extension/signature mismatches. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
auth.mjs:9
Finding
Shell Command Injection Through Configurable 1Password References<![CDATA[ ## Vulnerability Details **File Location**: `auth.mjs:9-10, 17-19` **Vulnerability Type**: OS command injection through shell interpolation **Risk Level**: High ### Vulnerable Code `auth.mjs:9-10, 17-19`: ```javascript const OP_VAULT = process.env.X_OP_VAULT || 'Agent Secrets'; const OP_ITEM = process.env.X_OP_ITEM || 'X API Key - wip-01'; /** * Read a field from 1Password. * Returns null if op CLI is not available or field not found. */ function opRead(field) { try { const ref = `op://${OP_VAULT}/${OP_ITEM}/${field}`; return execSync(`op read "${ref}" 2>/dev/null`, { encoding: 'utf8' }).trim() || null; } catch { return null; } } ``` ### Technical Analysis `X_OP_VAULT` and `X_OP_ITEM` are environment-controlled values. They are interpolated into a command string passed to `execSync`, which invokes a shell. Wrapping the generated reference in double quotes is not sufficient shell escaping. POSIX-compatible shells still perform command substitution inside double quotes, including constructs such as `$(command)` and backticks. An attacker able to control either environment variable can therefore introduce shell syntax that executes when `opRead` runs. Authentication resolution calls `opRead` for credential fields when the corresponding X credential is not available from the environment. Consequently, ordinary Skill operations can reach the vulnerable command construction. Using the 1Password CLI is related to credential retrieval, but invoking it through a shell is unnecessary. This creates local code-execution capability outside the Skill’s declared X API functionality. ### Attack Path 1. An attacker gains control over the environment used to launch the CLI or MCP server, including `X_OP_VAULT` or `X_OP_ITEM`. 2. The attacker places shell command-substitution syntax in one of those variables. 3. At least one direct X credential variable is left unset, causing `resolveAuth` to call `opRead`. 4. `opRead` builds a command st ...[truncated 1177 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Eliminate shell interpretation** - Replace `execSync` with `execFileSync` or `spawnSync`. - Pass every argument as a separate array element. - Do not enable `shell: true`. ```javascript import { execFileSync } from 'node:child_process'; function opRead(field) { try { const ref = `op://${OP_VAULT}/${OP_ITEM}/${field}`; return execFileSync('op', ['read', ref], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], }).trim() || null; } catch { return null; } } ``` 2. **Validate configurable names** - Restrict vault, item, and field names to an expected character set and reasonable length. - Reject control characters, newlines, command-substitution characters, and unexpected URI delimiters. - Prefer fixed configuration identifiers where runtime customization is not necessary. 3. **Harden execution** - Resolve the trusted `op` executable through controlled deployment configuration. - Run the Skill with a minimal `PATH`. - Apply an execution timeout and output-size limit. - Avoid inheriting unnecessary environment variables. 4. **Add security tests** - Test values containing `$()`, backticks, quotes, semicolons, newlines, and shell metacharacters. - Verify that supplied values are passed literally to the 1Password CLI and never evaluated by a shell. ]]>
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 Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (26)

Credential Access

High
Category
Privilege Escalation
Content
*   X_BEARER_TOKEN       ... app-only bearer token (read operations)
 *   X_API_KEY            ... OAuth 1.0a consumer key
 *   X_API_SECRET         ... OAuth 1.0a consumer secret
 *   X_ACCESS_TOKEN       ... OAuth 1.0a access token
 *   X_ACCESS_TOKEN_SECRET ... OAuth 1.0a access token secret
 *
 * 1Password (configurable via env):
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
*   X_BEARER_TOKEN       ... app-only bearer token (read operations)
 *   X_API_KEY            ... OAuth 1.0a consumer key
 *   X_API_SECRET         ... OAuth 1.0a consumer secret
 *   X_ACCESS_TOKEN       ... OAuth 1.0a access token
 *   X_ACCESS_TOKEN_SECRET ... OAuth 1.0a access token secret
 *
 * 1Password (configurable via env):
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
*   X_BEARER_TOKEN       ... app-only bearer token (read operations)
 *   X_API_KEY            ... OAuth 1.0a consumer key
 *   X_API_SECRET         ... OAuth 1.0a consumer secret
 *   X_ACCESS_TOKEN       ... OAuth 1.0a access token
 *   X_ACCESS_TOKEN_SECRET ... OAuth 1.0a access token secret
 *
 * 1Password (configurable via env):
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
bearerToken: process.env.X_BEARER_TOKEN || opRead('bearer token'),
    apiKey: process.env.X_API_KEY || opRead('api key'),
    apiSecret: process.env.X_API_SECRET || opRead('api secret'),
    accessToken: process.env.X_ACCESS_TOKEN || opRead('access token'),
    accessTokenSecret: process.env.X_ACCESS_TOKEN_SECRET || opRead('access token secret'),
  };
Confidence
87% confidence
Finding
This code actively retrieves access tokens from environment variables or 1Password, giving the skill access to credentials that can authorize X API actions. In this skill context that may be functionally necessary, but it is still a real credential-access capability and becomes dangerous because the same skill also supports write operations, so compromise or misuse of the skill could lead to account actions under those tokens.

Credential Access

High
Category
Privilege Escalation
Content
apiKey: process.env.X_API_KEY || opRead('api key'),
    apiSecret: process.env.X_API_SECRET || opRead('api secret'),
    accessToken: process.env.X_ACCESS_TOKEN || opRead('access token'),
    accessTokenSecret: process.env.X_ACCESS_TOKEN_SECRET || opRead('access token secret'),
  };

  if (!auth.bearerToken && !auth.apiKey) {
Confidence
87% confidence
Finding
This line retrieves the access token secret, completing a full OAuth 1.0a credential set when combined with the other fields. Access to the full token pair materially increases risk because it enables authenticated posting or other account actions if any surrounding code is abused, logged insecurely, or exposed through the agent runtime.

Known Vulnerable Dependency: fast-uri==3.1.0 — 7 advisory(ies): CVE-2026-13676 (fast-uri vulnerable to host confusion via failed IDN canonicalization); CVE-2026-18446 (fast-uri vulnerable to host confusion via backslash authority introducer); CVE-2026-75975 (fast-uri vulnerable to server-side request forgery via malformed IPv6 normalizat) +4 more

High
Category
Supply Chain
Confidence
89% confidence
Finding
fast-uri 3.1.0 is associated with multiple URI parsing and canonicalization issues, including host confusion and possible SSRF primitives. In a skill that integrates with external APIs and may process URLs, incorrect URI normalization can become security-relevant if attacker-controlled URLs are ever parsed or validated before outbound requests.

Known Vulnerable Dependency: hono==4.12.8 — 16 advisory(ies): CVE-2026-56762 (Hono missing validation of cookie name on write path in setCookie()); CVE-2026-47676 (Hono: app.mount() strips mount prefix using undecoded path, causing incorrect ro); CVE-2026-47675 (Hono: Cookie helper does not sanitize sameSite and priority, allowing Set-Cookie) +13 more

High
Category
Supply Chain
Confidence
88% confidence
Finding
hono 4.12.8 has numerous advisories affecting cookie handling, routing, and request processing. Because the MCP SDK depends on Hono for server functionality, these issues can matter if the skill runs as a networked service, especially where route normalization or cookie generation is security-sensitive.

Known Vulnerable Dependency: ip-address==10.1.0 — 2 advisory(ies): CVE-2026-69192 (ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco); CVE-2026-42338 (ip-address has XSS in Address6 HTML-emitting methods)

High
Category
Supply Chain
Confidence
80% confidence
Finding
ip-address 10.1.0 is flagged for address parsing inconsistencies and XSS in HTML-emitting methods. The XSS portion may be irrelevant unless the skill renders address-derived HTML, but the parsing inconsistency can still matter if IP-based validation, allowlisting, or rate limiting decisions are delegated to this library through express-rate-limit.

Known Vulnerable Dependency: path-to-regexp==8.3.0 — 2 advisory(ies): CVE-2026-4923 (path-to-regexp vulnerable to Regular Expression Denial of Service via multiple w); CVE-2026-4926 (path-to-regexp vulnerable to Denial of Service via sequential optional groups)

High
Category
Supply Chain
Confidence
84% confidence
Finding
path-to-regexp 8.3.0 is reported vulnerable to ReDoS/DoS via crafted route patterns or matching scenarios. Since this is used by router/express components in the transitive server stack, the practical risk depends on whether untrusted input can trigger pathological route matching, but it remains a genuine availability concern for exposed endpoints.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The authentication section instructs users to provide highly sensitive bearer and OAuth credentials and mentions automatic resolution from 1Password or environment variables, but it does not warn about secret handling, least privilege, storage risks, or the consequences of exposing write-capable tokens. In an agent setting, this is dangerous because users may grant broad credentials to automation without understanding that the skill can perform live actions on their account.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The README exposes write-capable and destructive operations such as posting, deleting tweets, bookmarking, and uploading media, but it does not include a clear caution section telling users that these actions can affect live accounts and should require explicit confirmation. In an agent-integrated context, this increases the chance of accidental or unauthorized state-changing actions if a user or orchestration layer enables the skill without understanding the risks.

External Transmission

Medium
Category
Data Exfiltration
Content
homepage: https://github.com/wipcomputer/wip-xai-x
metadata:
  category: social,api
  api_base: https://api.x.com/2
  capabilities:
    - api
    - fetch-posts
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The skill exposes tweet posting and deletion capabilities but does not clearly warn that these actions can create public, account-attributed content or permanently remove prior content. In an agent setting, missing consent and impact warnings increases the risk of unintended public actions, reputational harm, or destructive misuse if a user request is ambiguous or manipulated.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The helper spawns the external 1Password CLI to read secrets, which expands the skill's capability from interacting with the X API to also invoking a subprocess and accessing a local secret store. In an agent-skill context, this is security-relevant because any code path that can trigger auth resolution may reach beyond declared API usage and pull high-value credentials from the host environment.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The skill metadata says it can read posts, search, bookmark, post tweets, and upload media, but the code also exposes a delete_tweet actuator. This mismatch can mislead users or orchestrators about the true privilege/risk of the skill, enabling unexpected destructive actions against the user's X account.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
upload_media accepts an arbitrary local file_path, reads it with readFileSync, base64-encodes it, and sends it to the remote X API. In an agent setting, this creates a clear exfiltration path for sensitive local files if untrusted input can influence file_path, especially because there is no path restriction, consent gate, or warning in this file.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The file header advertises 7 tools including tweet deletion, but the provided skill metadata description says only 'Read posts, search tweets, get bookmarks, post tweets, upload media' and omits the destructive delete capability. This mismatch can mislead users or downstream agents about the true authority of the skill, increasing the chance of unintended destructive actions.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill exposes a destructive x_delete_tweet operation with no explicit confirmation, warning, or secondary validation in this file before invoking delete_tweet(params). In an agent-driven context, a prompt injection, misunderstanding, or accidental tool call could permanently remove content without the user realizing the action is irreversible.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The x_upload_media tool accepts an arbitrary local file path and is described only as uploading media, without a clear user-facing disclosure that local file contents will be transmitted to an external third-party service. In an MCP/agent setting, this raises data exfiltration risk if an agent is induced to upload sensitive local files under the guise of routine media handling.

Missing User Warnings

Low
Confidence
81% confidence
Finding
The skill describes reading bookmarks without noting that bookmarks may contain sensitive or private saved material tied to the authenticated user. In an agent workflow, omission of a privacy warning can lead to over-collection or disclosure of personal reading/saved-content history beyond what the user expected.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The media upload documentation does not state that local file contents are transmitted to X, which can cause accidental exfiltration of local images or videos if the file path is chosen carelessly. In an agent environment, users may not realize that specifying a local path results in external transfer of that file's contents.

Known Vulnerable Dependency: @hono/node-server==1.19.11 — 2 advisory(ies): CVE-2026-39406 (@hono/node-server: Middleware bypass via repeated slashes in serveStatic); GHSA-frvp-7c67-39w9 (Node.js Adapter for Hono: Path traversal in `serve-static` on Windows via encode)

Low
Category
Supply Chain
Confidence
78% confidence
Finding
The lockfile pins @hono/node-server 1.19.11, and the listed advisories describe path-handling flaws in static file serving, including repeated-slash bypass and Windows path traversal. Even though this skill is primarily an X/Twitter API integration and may not directly expose static serving, the dependency is present through the MCP SDK, so if any embedded server functionality is enabled these flaws could be reachable.

Known Vulnerable Dependency: body-parser==2.2.2 — 1 advisory(ies): CVE-2026-12590 (body-parser vulnerable to denial of service when invalid limit value silently di)

Low
Category
Supply Chain
Confidence
75% confidence
Finding
body-parser 2.2.2 is flagged for a denial-of-service issue related to invalid limit handling. This is a real dependency risk, but in this skill context it is likely only relevant if the MCP/server layer parses attacker-controlled HTTP bodies, making impact more operational than data-compromise oriented.

Known Vulnerable Dependency: qs==6.15.0 — 3 advisory(ies): CVE-2026-82417 (qs: Denial of Service via Attacker Controlled isBuffer); CVE-2026-8723 (qs has a remotely triggerable DoS: qs.stringify crashes with TypeError on null/u); CVE-2026-82562 (qs array-limit bypass via bracket-key comma parsing)

Low
Category
Supply Chain
Confidence
77% confidence
Finding
qs 6.15.0 has advisories for denial-of-service and parsing edge cases. In this package-lock context the issue is real, but likely limited to querystring/body parsing on any HTTP interface exposed by transitive dependencies, so the most likely effect is service degradation rather than direct compromise.

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "homepage": "https://github.com/wipcomputer/wip-xai-x",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.27.1",
    "@xdevplatform/xdk": "^0.4.0"
  }
}
Confidence
85% confidence
Finding
The dependency is specified with a caret range, which allows newer minor/patch versions to be installed over time. This can introduce supply-chain risk through unexpected behavior changes or a compromised upstream release, especially because this skill interfaces with external APIs and likely handles credentials/tokens.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.exposed_secret_literal

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
auth.mjs:19

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
auth.mjs:75