Back to skill

Security audit

Super Lobster

Security checks for vulnerabilities and agentic risk

Overview

This web-research skill is not clearly malicious, but it gives agents broad local execution and unsafe arbitrary URL/browser access that could expose local or internal data.

Install only if you are comfortable letting the agent fetch and render arbitrary web pages from the gateway and run local scripts. Prefer a hardened version that limits URLs to http/https public destinations, blocks private and local network ranges, keeps Chrome sandboxed in an isolated environment, bounds downloads and crawl limits, and requires explicit user approval before creating or executing new local programs.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
bin/fetch_url.py:10
Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Locations**: - `bin/fetch_url.py:10-17` - `bin/extract_main_text.py:9-14` - `bin/crawl_site.py:11-24` - `bin/render_url.py:8-19` - `bin/chrome_dump_dom.sh:7-8` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code `bin/fetch_url.py:10-17`: ```python parser = argparse.ArgumentParser() parser.add_argument('url') parser.add_argument('--timeout', type=int, default=20) args = parser.parse_args() headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36' } resp = requests.get(args.url, headers=headers, timeout=args.timeout) ``` `bin/extract_main_text.py:9-14`: ```python parser = argparse.ArgumentParser() parser.add_argument('url') parser.add_argument('--timeout', type=int, default=20) args = parser.parse_args() headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36' } resp = requests.get(args.url, headers=headers, timeout=args.timeout) ``` `bin/crawl_site.py:11-24`: ```python parser = argparse.ArgumentParser() parser.add_argument('url') parser.add_argument('--limit', type=int, default=10) parser.add_argument('--timeout', type=int, default=15) args = parser.parse_args() start = args.url start_host = urlparse(start).netloc headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36'} seen = set() queue = collections.deque([start]) results = [] while queue and len(results) < args.limit: url = queue.popleft() if url in seen: continue seen.add(url) try: resp = requests.get(url, headers=headers, timeout=args.timeout) ``` `bin/render_url.py:8-19`: ```python url = sys.argv[1] cmd = [ "/usr/bin/google-chrome-stable", "--headless=new", "--disable-gpu", "--no-sandbox", "--virtual-time-budget=15000", "--dump-do ...[truncated 2075 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only explicitly supported `http` and `https` URLs. 2. Resolve the destination hostname before connecting and reject every address in loopback, private, link-local, multicast, reserved, unspecified, and other non-public ranges for both IPv4 and IPv6. 3. Disable automatic redirects or implement a redirect handler that validates every destination before following it. 4. Protect against DNS rebinding by connecting to a previously validated address while preserving correct TLS hostname verification, or route traffic through a hardened outbound proxy. 5. Consider an explicit domain allowlist where the research task permits it. 6. Reject URLs containing embedded credentials and restrict destination ports. 7. Apply equivalent controls to browser rendering, not only the Python `requests` clients. 8. Enforce outbound firewall rules so application-level validation is not the sole control. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
bin/render_url.py:8
Finding
Chrome Argument Injection and Local-File Rendering Through Unvalidated Input<![CDATA[ ## Vulnerability Details **File Locations**: - `bin/render_url.py:8-19` - `bin/chrome_dump_dom.sh:7-8` **Vulnerability Type**: Argument injection and local-file disclosure **Risk Level**: High ### Vulnerable Code `bin/render_url.py:8-19`: ```python url = sys.argv[1] cmd = [ "/usr/bin/google-chrome-stable", "--headless=new", "--disable-gpu", "--no-sandbox", "--virtual-time-budget=15000", "--dump-dom", url, ] proc = subprocess.run(cmd, text=True, capture_output=True) ``` `bin/chrome_dump_dom.sh:7-8`: ```bash url="$1" exec /usr/bin/google-chrome-stable --headless=new --disable-gpu --no-sandbox --virtual-time-budget=15000 --dump-dom "$url" ``` ### Technical Analysis The wrappers pass attacker-influenced input directly to Chrome without requiring an HTTP or HTTPS URL. A `file://` target may cause Chrome to load and dump locally readable content. An input beginning with `-` may also be interpreted as an additional Chrome command-line switch because the wrappers do not reject option-like values or use an option terminator. The Python implementation avoids shell metacharacter injection by using an argument list, and the shell implementation correctly quotes the value, but neither measure prevents argument injection into Chrome itself. ### Attack Path 1. An attacker persuades the Agent to render a `file://` URL pointing to a known local path, or supplies a value beginning with `--`. 2. The wrapper starts Chrome and forwards the value without scheme or argument validation. 3. For a local-file URL, Chrome attempts to render the selected file and emits its DOM or contents. 4. For an injected switch, Chrome starts with attacker-selected behavior to the extent supported by its command-line parser. 5. The wrapper returns Chrome's output to the Agent, potentially exposing local information or altering the security characteristics of the browser process. ### Impact Assessment Successful exploitation may disclose files ...[truncated 390 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the input and require the normalized scheme to be exactly `http` or `https`. 2. Reject `file:`, `data:`, `javascript:`, `chrome:`, and all other unsupported schemes. 3. Reject values beginning with `-`, control characters, malformed hosts, and URLs containing embedded credentials. 4. Add a supported command-line option terminator before the validated URL as defense in depth. 5. Apply the SSRF protections described for the network-fetching tools. 6. Run Chrome under a dedicated account with no access to sensitive files. 7. Use an isolated, ephemeral browser profile and a restricted filesystem namespace. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
bin/render_url.py:10
Finding
Headless Chrome Processes Untrusted Web Content Without a Sandbox<![CDATA[ ## Vulnerability Details **File Locations**: - `bin/render_url.py:10-19` - `bin/chrome_dump_dom.sh:8` **Vulnerability Type**: Browser sandbox disabled **Risk Level**: High ### Vulnerable Code `bin/render_url.py:10-19`: ```python cmd = [ "/usr/bin/google-chrome-stable", "--headless=new", "--disable-gpu", "--no-sandbox", "--virtual-time-budget=15000", "--dump-dom", url, ] proc = subprocess.run(cmd, text=True, capture_output=True) ``` `bin/chrome_dump_dom.sh:8`: ```bash exec /usr/bin/google-chrome-stable --headless=new --disable-gpu --no-sandbox --virtual-time-budget=15000 --dump-dom "$url" ``` ### Technical Analysis Both rendering wrappers explicitly disable Chrome's process sandbox while loading arbitrary websites. Browser rendering processes attacker-controlled HTML, JavaScript, fonts, images, and other complex content. The browser sandbox is a principal containment boundary intended to limit the impact of renderer compromise. This flag does not independently create code execution, and exploitation would generally require a separate Chrome vulnerability. However, it materially increases the consequence of such a vulnerability by removing a major defense-in-depth layer. ### Attack Path 1. An attacker hosts a page containing content that exploits a vulnerability in the installed Chrome build. 2. The attacker causes the Agent to invoke a rendering wrapper for that page. 3. Chrome processes the malicious content with `--no-sandbox`. 4. If the browser exploit succeeds, the compromised process is not contained by Chrome's normal sandbox. 5. The exploit may access resources available to the gateway account and potentially alter local state. ### Impact Assessment The maximum impact is code execution with the privileges of the account running the Skill, subject to operating-system controls. This may expose files, environment data, network access, and writable workspace state. The practical exploitability depend ...[truncated 123 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--no-sandbox` and configure the host so Chrome's native sandbox operates correctly. 2. Run the browser under a dedicated, unprivileged service account. 3. If native sandboxing is unavailable, execute Chrome inside a disposable container or virtual machine with: - Dropped Linux capabilities. - A read-only root filesystem. - A small, ephemeral writable directory. - No access to Agent memory, credentials, or host sockets. - Seccomp/AppArmor/SELinux restrictions. - CPU, memory, process, and execution-time limits. - Restricted outbound network access. 4. Maintain Chrome on a supported, promptly patched release. 5. Use a fresh temporary profile for every invocation and remove it afterward. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
bin/fetch_url.py:17
Finding
Unbounded Downloads and User-Controlled Crawl Limits Permit Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Locations**: - `bin/fetch_url.py:17-34` - `bin/extract_main_text.py:14-24` - `bin/crawl_site.py:11-48` **Vulnerability Type**: Uncontrolled resource consumption **Risk Level**: Medium ### Vulnerable Code `bin/fetch_url.py:17-34`: ```python resp = requests.get(args.url, headers=headers, timeout=args.timeout) resp.raise_for_status() content_type = resp.headers.get('content-type', '') out = { 'url': resp.url, 'status_code': resp.status_code, 'content_type': content_type, 'encoding': resp.encoding, } if 'html' in content_type: soup = BeautifulSoup(resp.text, 'lxml') title = soup.title.get_text(' ', strip=True) if soup.title else None text = soup.get_text(' ', strip=True) out['title'] = title out['text_preview'] = text[:4000] out['html_preview'] = resp.text[:4000] else: out['body_preview'] = resp.text[:4000] ``` `bin/extract_main_text.py:14-24`: ```python resp = requests.get(args.url, headers=headers, timeout=args.timeout) resp.raise_for_status() html = resp.text text = trafilatura.extract(html, url=resp.url, include_links=True, include_images=False, favor_precision=True) or '' result = { 'url': resp.url, 'status_code': resp.status_code, 'title': trafilatura.extract_metadata(html, default_url=resp.url).title if trafilatura.extract_metadata(html, default_url=resp.url) else None, 'text': text, } json.dump(result, sys.stdout, ensure_ascii=False, indent=2) ``` `bin/crawl_site.py:11-13,22-48`: ```python parser.add_argument('url') parser.add_argument('--limit', type=int, default=10) parser.add_argument('--timeout', type=int, default=15) ``` ```python while queue and len(results) < args.limit: url = queue.popleft() if url in seen: continue seen.add(url) try: resp = requests.get(url, headers=headers, timeout=args.timeout) resp.raise_for_status() soup = BeautifulSoup(resp.text, 'lxml') title = soup.title.get_text( ...[truncated 2149 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use streaming requests and stop reading after a fixed maximum number of bytes. 2. Check `Content-Length` when present, while still enforcing the streaming cap because the header is untrusted and may be absent. 3. Set separate connection and read timeouts plus a strict wall-clock deadline for the entire operation. 4. Reject compressed responses whose decompressed size exceeds the configured limit. 5. Parse only bounded input and avoid repeatedly extracting metadata from the same document. 6. Validate `--limit` as a positive integer within a small fixed range, such as 1 through 100. 7. Add a global request budget, output-size limit, and per-host rate limit. 8. Apply operating-system or container-level CPU and memory limits. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
SKILL.md:34
Finding
Skill Instructions Grant Excessive Gateway Command-Execution Authority<![CDATA[ ## Vulnerability Details **File Locations**: - `SKILL.md:14` - `SKILL.md:34-38` **Vulnerability Type**: Excessive execution privileges and unsafe Agent guidance **Risk Level**: Medium ### Vulnerable Code `SKILL.md:14`: ```markdown 5. For multi-step processing, write a Python script under `/root/.openclaw/workspace/memory/tmp` and run it. ``` `SKILL.md:34-38`: ```markdown ## Coding and execution rules - You may write and execute Python or shell programs locally on the gateway. - Prefer Python for scraping, parsing, and data cleanup. - Keep scratch outputs in `/root/.openclaw/workspace/memory/tmp`. - Remove clearly temporary files after use unless they are likely to be reused. ``` ### Technical Analysis The declared functionality is web fetching, rendering, crawling, and text extraction, but the instructions grant blanket authority to create and execute arbitrary Python or shell programs on the gateway. They do not define a command allowlist, filesystem boundary, privilege separation mechanism, approval requirement, or sandbox. The designated scratch path is under `/root/.openclaw/workspace/memory`, which may contain state reused across Agent sessions. Although the instructions do not explicitly require poisoning persistent memory, storing attacker-influenced artifacts in a memory workspace increases exposure to persistent state modification. This broad authority exceeds the minimum permissions required to invoke the included, audited utilities. ### Attack Path 1. The Agent researches an attacker-controlled page. 2. The page contains indirect prompt-injection content directing the Agent to create or run a local script. 3. The Skill's own instructions explicitly authorize Python and shell execution on the gateway. 4. The Agent follows the injected workflow and writes code or data under the memory workspace. 5. The resulting process executes with the Agent's gateway privileges and can access resources available to that account. 6. If persistent w ...[truncated 587 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove blanket authorization for arbitrary shell and Python execution. 2. Restrict normal operation to the bundled, reviewed utilities and a narrowly defined set of arguments. 3. Require explicit user confirmation before generating or executing any new program. 4. Run necessary custom processing in a sandboxed, unprivileged environment with no access to credentials, host sockets, or persistent Agent state. 5. Use an ephemeral operating-system temporary directory rather than `/root/.openclaw/workspace/memory/tmp`. 6. Enforce filesystem allowlists, outbound network restrictions, process limits, and automatic cleanup. 7. Add explicit instructions that web content is untrusted data and must never be treated as executable Agent instructions. 8. Keep generated code and downloaded content out of long-term memory unless the user expressly approves persistence. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Vague Triggers

Medium
Confidence
95% confidence
Finding
The invocation text is extremely broad: it authorizes aggressive web research, crawling, extraction, local scripting, and command execution with little task-bound scoping. In an agentic environment, this can cause the skill to be selected for many unrelated prompts and then grant high-risk capabilities, increasing the chance of unnecessary network access or local execution.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill explicitly permits writing and executing local Python or shell programs on the gateway and deleting temporary files, but it provides no guardrails around filesystem scope, privilege level, destructive commands, or handling of sensitive data. In a powerful gateway environment, this can lead to arbitrary code execution, data loss, persistence, or accidental modification of system and workspace contents.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"--dump-dom",
    url,
]
proc = subprocess.run(cmd, text=True, capture_output=True)
if proc.returncode != 0:
    sys.stderr.write(proc.stderr)
    sys.exit(proc.returncode)
Confidence
98% confidence
Finding
This invokes a full browser on an attacker-controlled URL, which creates a server-side request forgery and untrusted content rendering primitive. Because Chrome is launched with '--no-sandbox', any browser exploit triggered by the remote page would execute without Chrome's normal containment, substantially increasing the risk of host compromise; even without RCE, it can be used to access internal network resources or cloud metadata endpoints and dump their rendered content.

Missing User Warnings

Low
Confidence
89% confidence
Finding
This code file performs outbound HTTP requests to user-supplied URLs, which transmits system/network metadata such as the User-Agent and may contact arbitrary hosts, but the script provides no confirmation prompt, user-facing notice, or explanatory comment/docstring about that behavior. For a generic crawler utility, this network activity is safety-relevant and not explicitly disclosed within the file.

Missing User Warnings

Low
Confidence
93% confidence
Finding
The script performs a server-side HTTP request to a fully user-supplied URL with no validation, allowlist, or warning. In an agent/skill context, this creates SSRF risk: an attacker can cause requests to internal services, cloud metadata endpoints, or other sensitive network locations, and the fetched content is then parsed and returned to the caller.

Missing User Warnings

Low
Confidence
93% confidence
Finding
The script performs a server-side HTTP request to a fully user-supplied URL with no validation, allowlist, or scheme restrictions. In an agent or automation context, this can enable SSRF behavior, allowing access to internal services, cloud metadata endpoints, or other network-reachable resources that the caller should not be able to probe through the skill.

Static analysis

No suspicious patterns detected.