Back to skill

Security audit

X Mobile Longshot / X 真机感长截图导出

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent X screenshot tool, but it needs review because unsafe filename handling can run local code and the browser can be pointed at non-X or internal URLs.

Install only if you trust the users and prompts that will control its command arguments. Avoid using user-supplied output filenames, run it in an isolated workspace with limited network access, and prefer a version that validates X URLs, blocks internal network destinations, and passes paths to Python as data rather than generated code.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/render_x_longshot.js:126
Finding
Arbitrary Python Code Execution Through Unsafely Interpolated Output Paths## Vulnerability Details **File Location**: `scripts/render_x_longshot.js`, lines 126-150 **Vulnerability Type**: Python source-code injection **Risk Level**: High ### Vulnerable Code ```javascript const py = ` from PIL import Image raw = Image.open(r'''${rawPng}''').convert('RGB') top = Image.open(r'''${topPng}''').convert('RGB') out = raw.copy() crop_h = min(${args.topFixPx}, top.size[1], out.size[1]) out.paste(top.crop((0,0,top.size[0],crop_h)), (0,0)) out.save(r'''${args.outPng}''') print(r'''${args.outPng}''') `; runPython(py); if (!args.noPdf) { const pyPdf = ` from PIL import Image img = Image.open(r'''${args.outPng}''').convert('RGB') img.save(r'''${args.outPdf}''', 'PDF', resolution=144.0) print(r'''${args.outPdf}''') `; runPython(pyPdf); } ``` The generated programs are executed by the following helper: ```javascript function runPython(code) { const r = spawnSync('python3', ['-c', code], { encoding: 'utf8' }); if (r.status !== 0) { throw new Error(r.stderr || r.stdout || 'python3 failed'); } return r.stdout.trim(); } ``` ### Technical Analysis The values supplied through `--out-png` and `--out-pdf` are interpolated directly into Python source code enclosed by raw triple-quoted string literals. They are then passed to `python3 -c`. Although `spawnSync` is invoked without a shell, this only prevents shell metacharacter expansion. It does not prevent injection into the Python program itself. A path containing a terminating `'''` sequence can close the intended string literal and append arbitrary Python statements. The PDF path is a direct exploitation point because the attacker can terminate the path passed to `img.save`, append a Python expression such as an `os` or `subprocess` invocation, and comment out the remaining generated source. The earlier image processing succeeds using a legitimate PNG path before the malicious PDF- ...[truncated 1591 chars]
Remediation
## Remediation Suggestions Do not embed caller-controlled values in executable Python source. 1. Move the Pillow operations into a fixed Python helper script and pass all paths as ordinary command-line arguments: ```javascript spawnSync('python3', [ helperScript, '--raw', rawPng, '--top', topPng, '--output', args.outPng, '--top-fix-px', String(args.topFixPx) ]); ``` The helper should retrieve these values through `argparse` or `sys.argv`, where they remain data rather than Python syntax. 2. Alternatively, send a JSON object to a fixed Python program through standard input and parse it with `json.load(sys.stdin)`. 3. Validate and normalize output paths before use. Require a conservative filename policy and constrain resolved paths to an approved output directory. 4. Reject null bytes, control characters, newline characters, and unexpected path components. This validation should be defense in depth rather than the primary injection mitigation. 5. Add regression tests using filenames containing quotes, triple quotes, backslashes, newlines, Unicode characters, and Python metacharacters. Verify that these values are either safely handled as filenames or explicitly rejected and never interpreted as code.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/render_x_longshot.js:109
Finding
Server-Side Request Forgery Through Unrestricted Browser Navigation## Vulnerability Details **File Location**: `scripts/render_x_longshot.js`, lines 21 and 109-121 **Vulnerability Type**: Unrestricted URL navigation and server-side request forgery **Risk Level**: Medium ### Vulnerable Code The URL is accepted without validating its scheme, hostname, destination address, or redirects: ```javascript if (a === '--url') out.url = next(); ``` It is then opened twice from the execution environment: ```javascript try { await page.goto(args.url, { waitUntil: 'domcontentloaded', timeout: 45000 }); await page.waitForTimeout(args.waitMs); await clickIgnore(page); await page.waitForTimeout(700); await hideOverlays(page); await page.waitForTimeout(1000); const rawPng = args.outPng.replace(/\.png$/i, '.raw.png'); const topPng = args.outPng.replace(/\.png$/i, '.top.png'); await page.screenshot({ path: rawPng, fullPage: true }); await page.goto(args.url, { waitUntil: 'domcontentloaded', timeout: 45000 }); ``` ### Technical Analysis The skill is documented as an X/Twitter renderer, but it does not enforce that the supplied URL belongs to an approved X domain. Any destination accepted by Playwright may be passed to `page.goto`. Consequently, the headless browser can initiate requests using the network access of the machine running the skill. This may include HTTP services bound to loopback interfaces, private network addresses, link-local services, administrative interfaces, or cloud metadata endpoints. Restricting only the initial string would also be insufficient because an approved public URL could redirect to a prohibited destination. DNS resolution can similarly map a hostname to an internal address or change between validation and connection. Both browser requests and redirects therefore require enforcement. The full-page screenshot and optional PDF provide a direct mechanism for returning rendered response content to the caller ...[truncated 1881 chars]
Remediation
## Remediation Suggestions 1. Enforce an explicit destination allowlist consistent with the skill's documented purpose. For example, permit only HTTPS URLs on approved X hostnames such as `x.com`, plus any explicitly required and reviewed aliases. 2. Reject: - Non-HTTPS schemes. - URLs containing embedded credentials. - Loopback, private, link-local, multicast, unspecified, reserved, and cloud-metadata addresses. - Hostnames outside the approved allowlist. - Unexpected ports. 3. Resolve the hostname and validate every returned IPv4 and IPv6 address before navigation. Do not rely solely on textual hostname checks. 4. Intercept browser requests with Playwright routing and apply the same policy to every navigation, redirect, subresource request, popup, worker request, and dynamically loaded resource: ```javascript await context.route('**/*', async route => { const requestUrl = new URL(route.request().url()); if (!(await isAllowedDestination(requestUrl))) { return route.abort(); } return route.continue(); }); ``` 5. Revalidate redirect destinations rather than trusting the original URL. 6. Run Chromium in an isolated network namespace or container with outbound access restricted to the minimum required public destinations. Application-level validation should be combined with network-level egress controls. 7. Add tests for loopback addresses, private IPv4 ranges, IPv6 loopback and private ranges, decimal or encoded IP representations, DNS rebinding scenarios, redirects to internal services, embedded credentials, and non-HTTPS schemes.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
Findings (2)

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The markdown sets defaults to `zh-CN` and `Asia/Shanghai`, which imposes a language/locale configuration on all uses of the skill. The file does not offer a user choice or explain why this locale constraint is necessary for a region-specific purpose, so it conflicts with the language/locale policy requirement.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
This code hard-codes `locale: 'zh-CN'` and `timezoneId: 'Asia/Shanghai'` for every run, which imposes a specific language/locale setting on users. The file does not show any opt-in, configurability, or justification that would make this locale restriction acceptable under the stated policy.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/render_x_longshot.js:90