Back to skill

Security audit

gpu-cluster-monitor

Security checks for vulnerabilities and agentic risk

Overview

This skill is a real web scraper, but it can browse arbitrary targets from inside Docker with weak isolation and unclear safeguards.

Install only if you are comfortable running an active browser-based scraper in Docker. Use it only on authorized public URLs, avoid authenticated/internal targets, run it in an isolated container/network, make mounts read-only where possible, and pin/review the Docker image and dependencies before use.

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
assets/main_handler.js:80
Finding
Unrestricted URL Retrieval Enables Server-Side Request Forgery## Vulnerability Details **File Location**: `assets/main_handler.js:10-11, 80-83`; also present in `assets/youtube_handler.js:3-4, 32` **Vulnerability Type**: Server-Side Request Forgery through unrestricted browser navigation **Risk Level**: High ### Vulnerable Code ```javascript const targetUrl = process.argv[2]; const videoId = targetUrl?.split('v=')[1]?.split('&')[0]; const mode = targetUrl?.includes('youtube.com') ? 'YOUTUBE' : 'GENERIC'; ``` ```javascript } else { // Generic dynamic page scraping await page.goto(targetUrl, { waitUntil: 'networkidle' }); const title = await page.title(); const content = await page.evaluate(() => document.body.innerText); console.log(JSON.stringify({ status: 'SUCCESS', type: 'GENERIC', title, data: content.substring(0, 10000) })); } ``` The dedicated YouTube handler also navigates directly to an unvalidated argument: ```javascript const targetUrl = process.argv[2]; const videoId = targetUrl.split('v=')[1]?.split('&')[0]; ``` ```javascript await page.goto(targetUrl, { waitUntil: 'networkidle' }); ``` ### Technical Analysis The application accepts a URL directly from the command line and passes it to Playwright without validating its protocol, hostname, port, resolved IP address, or redirect destinations. The generic handler then reads the response body and prints up to 10,000 characters to standard output. Consequently, the browser can be directed to resources reachable from the container but not necessarily reachable by the party supplying the URL. Potential destinations include loopback interfaces, private network ranges, link-local services, internal administration panels, and cloud instance metadata endpoints. Checking whether the input contains `youtube.com` is not a security boundary. Generic URLs receive no destination restrictions, and substring matching does not establish tha ...[truncated 1274 chars]
Remediation
## Remediation Suggestions 1. Parse input with the standard `URL` class and allow only explicitly required schemes, normally `https:` and optionally `http:`. 2. Reject URLs containing credentials, unsupported ports, malformed hostnames, or noncanonical representations. 3. Resolve the destination hostname and reject every address in loopback, private, link-local, multicast, reserved, unspecified, carrier-grade NAT, and cloud metadata ranges for both IPv4 and IPv6. 4. Explicitly block metadata endpoints such as `169.254.169.254` and their IPv6 or provider-specific equivalents. 5. Disable automatic redirects or independently validate every redirect destination before following it. 6. Protect against DNS rebinding by validating the address actually used for the connection, not only an earlier DNS lookup. 7. Prefer a strict hostname allowlist if the skill only needs to support known public services. 8. Apply outbound network controls at the container or host firewall layer so the browser cannot reach private networks or metadata services. 9. Validate YouTube origins using exact parsed hostnames rather than substring matching, and validate the video identifier with the expected format. 10. Add automated tests covering loopback, private IPv4, IPv6 loopback, link-local addresses, alternate numeric IP encodings, redirect chains, and DNS rebinding scenarios.

T09 · Insecure Skill Coding Practices

Warning
Location
assets/main_handler.js:18
Finding
Browser Sandboxing Is Disabled While Processing Untrusted Web Content## Vulnerability Details **File Location**: `assets/main_handler.js:18-23`; `assets/youtube_handler.js:7-12`; writable bind mount documented at `SKILL.md:13-16` **Vulnerability Type**: Unsafe browser isolation configuration **Risk Level**: Medium ### Vulnerable Code ```javascript const crawler = new PlaywrightCrawler({ launchContext: { launchOptions: { headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'], // Required for Docker }, }, ``` The same unsafe browser arguments are used by the secondary handler: ```javascript const crawler = new PlaywrightCrawler({ launchContext: { launchOptions: { headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'], }, }, ``` The documented execution command mounts the source directory without a read-only option: ```bash docker run -t --rm -v $(pwd)/skills/deep-scraper/assets:/usr/src/app/assets clawd-crawlee node assets/main_handler.js [TARGET_URL] ``` ### Technical Analysis The application loads attacker-selected web pages while launching Chromium with both `--no-sandbox` and `--disable-setuid-sandbox`. These options remove browser process-isolation controls intended to constrain a compromised renderer. Disabling the browser sandbox does not itself create a browser exploit. It materially increases the consequence of a successful vulnerability in Playwright's bundled browser or its rendering components because malicious web content would face fewer barriers before reaching the browser process's container-level privileges. The documented Docker command also bind-mounts the skill's `assets` directory without the `:ro` option. Docker bind mounts are writable by default unless explicitly restricted. Therefore, a browser process that is compromised inside the container may be able to modify host-backed JavaScript files, subject to the effective ...[truncated 1465 chars]
Remediation
## Remediation Suggestions 1. Run Chromium with its sandbox enabled and remove `--no-sandbox` and `--disable-setuid-sandbox`. 2. Configure the image to run the application as a dedicated, unprivileged non-root user. 3. Install and configure the browser sandbox correctly in the container rather than disabling it for convenience. 4. Mount application code read-only, for example with `-v ...:/usr/src/app/assets:ro`. 5. Use a read-only container root filesystem and provide narrowly scoped temporary storage only where required. 6. Drop all unnecessary Linux capabilities and enable an appropriate seccomp and AppArmor or SELinux policy. 7. Do not use privileged mode or host networking. 8. Restrict outbound network access to destinations required by the scraping task. 9. Pin and regularly update Playwright and its browser binaries to versions containing current security fixes. 10. Treat browser output and downloaded content as untrusted, and destroy the isolated container after every run.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (12)

Memory Manipulation

High
Category
Memory Poisoning
Content
async requestHandler({ page, log }) {
        log.info(`Deep-Scraper starting in ${mode} mode for: ${targetUrl}`);
        
        // Clear context to ensure a fresh session (avoid cache leakage)
        const context = page.context();
        await context.clearCookies();
Confidence
80% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding
Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill instructs users to run an active scraping container against external sites while bind-mounting a host directory, but it does not clearly warn that the container can write collected data to the host filesystem and generate network traffic to third-party services. In a security-sensitive agent environment, that omission can lead to unintended data persistence, compliance issues, or risky execution without informed user consent.

Intent-Code Divergence

Medium
Confidence
84% confidence
Finding
The file header presents the skill as a generic "Deep-Scraper" optimized for container execution, but the implementation includes targeted YouTube-specific behavior: extracting a video ID, intercepting timedtext API requests, inducing UI interaction, and directly fetching transcript data. This is more than an incomplete comment because the documented intent suggests general scraping while the code embeds a distinct transcript-extraction workflow.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The generic mode accepts an arbitrary URL and then extracts the full page title and body text from whatever content is rendered. In an agent or containerized environment, this broad scraping behavior can enable collection of sensitive information from internal dashboards, authenticated pages, or user-provided targets without meaningful scope restriction or consent controls.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This code navigates to a user-supplied YouTube URL and later fetches the transcript endpoint, transmitting the target URL and related request metadata over the network. Although there is internal logging, there is no user-facing prompt, warning comment, or docstring disclosing that the skill will contact external services and retrieve remote content.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The code comments and primary behavior imply transcript extraction, but on failure it silently returns the video's visible description instead. This creates a data-integrity and scope-creep issue: downstream consumers may believe they received transcript-only content while actually receiving different page text, which can cause unintended collection, processing, or disclosure of data.

Tool Parameter Abuse

Low
Category
Tool Misuse
Content
## Standard Interface (CLI)
```bash
docker run -t --rm -v $(pwd)/skills/deep-scraper/assets:/usr/src/app/assets clawd-crawlee node assets/main_handler.js [TARGET_URL]
```

## Output Specification (JSON)
Confidence
15% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
The script emits user-visible status and result messages in Chinese, such as the log at L16 and similar strings throughout the file. This forces a specific language choice without offering the user a language or locale option, which matches the language/locale policy concern.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"author": "Joseph",
  "license": "MIT",
  "dependencies": {
    "crawlee": "^3.0.0",
    "playwright": "^1.40.0"
  },
  "openclaw": {
Confidence
90% confidence
Finding
The dependency uses a caret range instead of an exact pinned version, so installs may resolve to different releases over time. This weakens build reproducibility and can unexpectedly pull in a vulnerable or malicious upstream update, which matters for a network-facing scraping skill that runs browser automation inside containers.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"license": "MIT",
  "dependencies": {
    "crawlee": "^3.0.0",
    "playwright": "^1.40.0"
  },
  "openclaw": {
    "requires": {
Confidence
94% confidence
Finding
The Playwright dependency is also version-ranged with a caret, allowing different versions to be installed in future environments. Because this package drives browser automation and may download browser components, unpinned resolution increases supply-chain and reproducibility risk.

Unverifiable Dependency: playwright has 1 known advisory(ies) (CVE-2025-59288 (Playwright downloads and installs browsers without verifying the authenticity of)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
86% confidence
Finding
The manifest includes Playwright without pinning an exact version, and there is a known advisory affecting some Playwright releases related to browser download authenticity verification. Without an exact version or lockfile evidence, it is not possible to confirm that deployed installs avoid the affected range, creating a plausible supply-chain exposure in a tool that automates browser fetching and execution.

Static analysis

No suspicious patterns detected.