Back to skill

Security audit

web-screenshot

Security checks for vulnerabilities and agentic risk

Overview

This screenshot skill does what it claims, but it gives browser and file-write capabilities broad enough that users should review it before installing.

Install only if you trust the environment where it will run. Use it for public webpages, avoid internal or sensitive URLs, keep outputs under a dedicated temporary directory, and prefer a version that pins Playwright, restricts URL destinations, prevents overwrites outside its artifact directory, and runs Chromium with sandboxing or external containment.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/screenshot.sh:39
Finding

Unrestricted URL Navigation Enables Server-Side Request Forgery

Content
View full analysis
[output_path] [--fullpage|--pdf]" exit 1 fi ``` PDF navigation path: ```javascript const { chromium } = require('playwright'); const url = process.argv[2]; const output = process.argv[3]; (async () => { const browser = await chromium.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage({ viewport: { width: 1440, height: 900 } }); await page.emulateMedia({ media: 'screen' }); await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 20000 }); ``` Screenshot navigation path: ```javascript const { chromium } = require('playwright'); const url = process.argv[2]; const output = process.argv[3]; const fullPage = process.argv[4] === 'true'; (async () => { const browser = await chromium.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage({ viewport: { width: 1440, height: 900 } }); await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 20000 }); ``` ### Technical Analysis The URL is taken directly from the first command-line argument and passed to Playwright's `page.goto()` function. The script does not validate the URL scheme, hostname, resolved IP address, destination port, or redirect chain. Because the request originates from the host running the Skill, the browser may reach resources that are inaccessible to the external requester. Potential targets include: - Loopback services such as `127.0.0.1` and `localhost` - RFC 1918 private-network services - Link-local endpoints - Cloud instance metadata endpoints - Internal administrative dashboards and development services ...[truncated 1499 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/screenshot.sh:19
Finding

Caller-Controlled Output Path Permits Arbitrary File Creation or Overwrite

Content
View full analysis
{ const browser = await chromium.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage({ viewport: { width: 1440, height: 900 } }); await page.emulateMedia({ media: 'screen' }); await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 20000 }); await page.waitForTimeout(3000); await page.pdf({ path: output, format: 'A4', printBackground: true, margin: { top: '1cm', bottom: '1cm' } }); ``` Screenshot output sink: ```javascript const output = process.argv[3]; const fullPage = process.argv[4] === 'true'; (async () => { const browser = await chromium.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage({ viewport: { width: 1440, height: 900 } }); await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 20000 }); await page.waitForTimeout(3000); await page.screenshot({ path: output, fullPage: fullPage }); ``` ### Technical Analysis The optional output path is accepted directly from the caller. The script creates the supplied parent directory and passes the path to Playwright without enforcing an output root, canonicalizing the path, checking whether the destination already exists, or preventing symbolic-link traversal. Shell quoting prevents ordinary command injection through the path, but it does not prevent filesystem abuse. Abso ...[truncated 1664 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/screenshot.sh:36
Finding

Chromium Sandbox Is Disabled While Rendering Attacker-Selected Content

Content
View full analysis
{ const browser = await chromium.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); ``` Screenshot branch: ```javascript const { chromium } = require('playwright'); const url = process.argv[2]; const output = process.argv[3]; const fullPage = process.argv[4] === 'true'; (async () => { const browser = await chromium.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); ``` The inline usage documented by the Skill has the same behavior: ```javascript const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch({ headless: true, args: ['--no-sandbox'] }); ``` ### Technical Analysis The script explicitly starts Chromium with `--no-sandbox` and `--disable-setuid-sandbox`. These arguments remove browser process-isolation protections that are intended to limit the impact of a renderer compromise. This is especially dangerous because the browser navigates to a caller-selected URL and executes the target page's JavaScript. Browser content is therefore an untrusted active-code input. If the Chromium build contains an exploitable renderer, JavaScript engine, image parser, font parser, or document-processing vulnerability, disabling the sandbox substantially reduces the barriers between compromised renderer code and the operating-system environment. The code does not itself include a browser exploit, so host compromise requires a separate vulnerability in Chromium or one of its content-processing components. Nevertheless, the configuration unnecessarily converts malicious web content into a higher- ...[truncated 1298 chars]
Remediation
View remediation
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The description says to use the skill whenever the user asks to screenshot a webpage, save a snapshot, archive a screenshot, do QA comparison, or export to PDF, but it does not clearly bound when this skill should or should not activate. Because these are common phrasings and no exclusion conditions or negative examples are provided, the invocation scope is ambiguous for a markdown skill description.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The bullets include broad conditions like "截取某个网页" and "快速查看某个 URL 的视觉效果," which could match many ordinary browsing or preview requests. The section does not clearly distinguish this skill from other browsing, preview, or reporting skills, increasing the risk of unintended invocation.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
86% confidence
Finding

The skill depends on Playwright from an npx cache path rather than a clearly pinned, reproducible version. That creates supply-chain and reproducibility risk: a different cached package set or refreshed cache could change runtime behavior or introduce malicious code without any change to the skill itself.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The natural-language description explicitly frames the tool around Chinese websites and the section header later says "When to Use(中文场景)," which can imply a locale-specific bias in activation or usage. There is no explicit opt-in, user language choice, or documented justification that this skill is intentionally region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
74% confidence
Finding

The heading "When to Use(中文场景)" presents a locale-specific framing in natural language that may steer use toward one language context by default. Because no user choice or necessity is explained, this can be read as an unjustified locale constraint.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.