Back to skill

Security audit

Browser Automation

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real browser automation helper, but it needs review because it runs an unsandboxed browser against arbitrary URLs and installs Puppeteer without a pinned dependency set.

Install only in an isolated, unprivileged environment with limited network access, do not expose secrets or internal services to the browser process, require explicit user confirmation before submitting forms or using credentials/cookies, restrict allowed URL targets where possible, and pin Puppeteer with a reviewed lockfile before production use.

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/scrape.js:15
Finding
Unrestricted Browser Navigation Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/scrape.js:15-40`, `scripts/crawl.js:15-50`, and `scripts/screenshot.js:16-42` **Vulnerability Type**: Server-Side Request Forgery through unvalidated browser navigation **Risk Level**: High ### Vulnerable Code `scripts/scrape.js:15-40`: ```javascript const url = process.argv[2]; const selector = process.argv[3] || 'body'; if (!url) { console.error('Usage: node scrape.js <url> [selector]'); console.error('Example: node scrape.js https://example.com h2'); process.exit(1); } (async () => { const browser = await puppeteer.launch({ headless: 'new', args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage(); // Set a neutral user agent await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'); console.error(`Fetching: ${url}`); await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 }); ``` `scripts/crawl.js:15-50`: ```javascript const url = process.argv[2]; const selector = process.argv[3]; const maxPages = parseInt(process.argv[4]) || 10; if (!url || !selector) { console.error('Usage: node crawl.js <url> <selector> [maxPages]'); console.error('Example: node crawl.js https://example.com/products .item 5'); process.exit(1); } (async () => { const browser = await puppeteer.launch({ headless: 'new', args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage(); // Set a neutral user agent await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'); let allData = []; for (let i = 1; i <= maxPages; i++) { // Build page URL - append ?page=X or &page=X let pageUrl = url; if (i > 1) { pageUrl = url.includes('?') ? `${url}&page=${i}` : `${url}?page=${i}`; } console.error(`[${i}/ ...[truncated 3321 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Accept only explicitly supported protocols, preferably `https:` and, where necessary, `http:`. 2. Reject URLs containing embedded credentials or malformed hostnames. 3. Resolve the hostname before navigation and reject every address in loopback, private, link-local, multicast, reserved, and cloud-metadata ranges for both IPv4 and IPv6. 4. Validate all addresses returned by DNS, not only the first result. 5. Revalidate the destination after every redirect. Consider disabling automatic redirects and processing each `Location` header through the same policy. 6. Use an explicit hostname allowlist when the intended scraping targets are known. 7. Run the browser in a network-isolated environment that cannot route to internal services or metadata endpoints. 8. Apply egress firewall rules as a second enforcement layer. 9. Add tests covering IPv4, IPv6, alternative address notation, redirects, DNS rebinding, internal DNS names, and metadata addresses. 10. Ensure URL validation and the actual connection use consistent DNS results to reduce time-of-check/time-of-use bypasses. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/scrape.js:24
Finding
Chromium Sandbox Is Explicitly Disabled for Untrusted Web Content<![CDATA[ ## Vulnerability Details **File Location**: `scripts/scrape.js:24-28`, `scripts/crawl.js:25-29`, and `scripts/screenshot.js:26-30` **Vulnerability Type**: Unsafe browser security configuration **Risk Level**: High ### Vulnerable Code `scripts/scrape.js:24-28`: ```javascript (async () => { const browser = await puppeteer.launch({ headless: 'new', args: ['--no-sandbox', '--disable-setuid-sandbox'] }); ``` `scripts/crawl.js:25-29`: ```javascript (async () => { const browser = await puppeteer.launch({ headless: 'new', args: ['--no-sandbox', '--disable-setuid-sandbox'] }); ``` `scripts/screenshot.js:26-30`: ```javascript (async () => { const browser = await puppeteer.launch({ headless: 'new', args: ['--no-sandbox', '--disable-setuid-sandbox'] }); ``` The same unsafe configuration is also promoted in `SKILL.md:42-45`, `README.md:92-95`, and `references/puppeteer-api.md:7-18`. ### Technical Analysis The `--no-sandbox` and `--disable-setuid-sandbox` flags explicitly disable Chromium's process sandbox. This sandbox is a major isolation boundary intended to limit the operating-system resources available to compromised renderer processes. The skill is specifically designed to load caller-selected websites, meaning Chromium routinely processes arbitrary and potentially malicious HTML, JavaScript, images, fonts, and other complex content. Disabling the sandbox substantially increases the consequences of a Chromium renderer vulnerability: an exploit that would otherwise remain constrained within a sandboxed renderer may gain the privileges of the Node.js/Chromium process. The configuration does not independently create code execution; exploitation requires a compatible browser vulnerability or another renderer compromise. However, it removes an important defense-in-depth boundary from a high-risk use case involving untrusted remote content. The API reference states that `--no-sandbox` is required for Linux, which is o ...[truncated 1493 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--no-sandbox` and `--disable-setuid-sandbox` from all default launch configurations. 2. Run Chromium as a dedicated, unprivileged operating-system user with its supported sandbox enabled. 3. Correct the documentation so that disabling the sandbox is not presented as generally required on Linux. 4. If a constrained platform cannot support Chromium's sandbox, run the entire browser workload inside a strongly isolated disposable container or virtual machine. 5. Do not run the scripts as root. 6. Do not mount secrets, SSH keys, cloud credentials, Docker sockets, or sensitive host directories into the browser environment. 7. Apply restrictive filesystem permissions, seccomp/AppArmor/SELinux controls, process limits, and network egress restrictions. 8. Keep Puppeteer and its bundled Chromium version patched and subject browser updates to security review. 9. Destroy the isolated execution environment after each untrusted browsing task. ]]>

T08 · Insecure Dependencies

Warning
Location
README.md:5
Finding
Unpinned Puppeteer Installation Creates a Non-Reproducible Supply Chain<![CDATA[ ## Vulnerability Details **File Location**: `README.md:5-8`, `README.md:122-127`, and `SKILL.md:29-31` **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Medium ### Vulnerable Code `README.md:5-8`: ```markdown ## Install ```bash npm install puppeteer ``` ``` `README.md:122-127`: ```markdown ## Requirements - Node.js 18+ - npm - Puppeteer (installed via `npm install puppeteer`) ``` `SKILL.md:29-31`: ```markdown # Install Puppeteer npm install puppeteer ``` ### Technical Analysis The project does not include a `package.json` with an exact Puppeteer version or a committed lockfile. The documented command therefore resolves the current package version and transitive dependency graph from the configured npm registry at installation time. This makes installation non-reproducible: two installations performed at different times can retrieve different code even when the reviewed skill files remain unchanged. Puppeteer's installation process also obtains browser artifacts, increasing the amount of externally sourced executable content involved in setup. No evidence was found that the project intentionally references a malicious, misspelled, or attacker-controlled package. The risk arises from unconstrained future resolution and the absence of integrity-pinned dependency metadata. ### Attack Path 1. An operator follows the documented `npm install puppeteer` instruction. 2. npm resolves the dependency version and transitive graph available from the configured registry at that time. 3. The resolved release may differ from the version previously reviewed or tested. 4. If a future release, transitive dependency, registry account, mirror, or package-delivery path is compromised, npm retrieves the affected content. 5. Package lifecycle scripts or subsequently imported package code execute with the privileges of the installing or runtime user. 6. Compromised code could access files, environment variables, credentials, or ...[truncated 609 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a `package.json` that declares a reviewed, exact Puppeteer version rather than a floating range. 2. Generate and commit `package-lock.json` so the complete dependency graph and integrity hashes are recorded. 3. Use `npm ci` in automated and production installations instead of an unconstrained `npm install`. 4. Review Puppeteer, transitive dependency, and bundled Chromium updates before changing the lockfile. 5. Configure npm to use an approved registry and protect against untrusted user-level registry overrides. 6. Run dependency installation as an unprivileged user in an isolated build environment. 7. Generate a software bill of materials and scan the locked dependency graph for known vulnerabilities. 8. Verify the provenance and integrity of browser artifacts downloaded during Puppeteer installation where supported. 9. Avoid exposing production credentials or sensitive host mounts during dependency installation. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger language is broad enough to match many generic requests involving browsing, screenshots, data extraction, or page interaction, which can cause this skill to activate in situations where a less powerful or safer skill would be more appropriate. Because this skill performs live browser automation and can interact with third-party sites, over-selection increases the chance of unintended network access, scraping, form submission, or local file creation.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill does not clearly warn that using it will initiate live requests to external websites, may fill and submit forms, and may save screenshots or scraped content locally. In an agent setting, missing this disclosure makes it easier for users or higher-level planners to invoke powerful browser actions without appreciating the privacy, consent, and side-effect risks.

Missing User Warnings

Low
Confidence
83% confidence
Finding
This markdown file includes an example that sets an Authorization header with a bearer token, which is a network operation involving credentials. The surrounding documentation provides no warning that requests may transmit sensitive authentication data or that users should handle tokens carefully.

Missing User Warnings

Low
Confidence
80% confidence
Finding
The documentation shows reading and setting cookies, including a session cookie value, which can affect privacy and authentication state. There is no user-facing warning that cookie operations may expose or modify sensitive session data.

Static analysis

No suspicious patterns detected.