Back to skill

Security audit

AK RSS 24h Brief

Security checks for vulnerabilities and agentic risk

Overview

This RSS brief skill is mostly coherent, but it needs Review because its feed fetcher can contact arbitrary or internal URLs from an OPML file without validation or resource limits.

Install only if you are comfortable with it making outbound requests to every URL in the OPML feed list. Prefer trusted OPML files, run it in a sandboxed environment without access to internal networks or sensitive local files, and keep workers/feed counts conservative until URL and response-size validation are added.

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
scripts/generate_brief.py:18
Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery and Local Resource Access<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_brief.py`, lines 18–23, 312, 326, 334, and 342 **Vulnerability Type**: Server-Side Request Forgery (SSRF) and unrestricted URI scheme handling **Risk Level**: High ### Vulnerable Code ```python def fetch_text(url: str, timeout: int) -> str: req = urllib.request.Request(url, headers={"User-Agent": "openclaw-hn-rss-brief/1.0"}) with urllib.request.urlopen(req, timeout=timeout) as r: charset = r.headers.get_content_charset() or "utf-8" return r.read().decode(charset, errors="replace") ``` The initial OPML source is retrieved without destination validation: ```python if args.opml_url: opml_text = fetch_text(args.opml_url, timeout=args.timeout) else: with open(args.opml_file, 'r', encoding='utf-8') as f: opml_text = f.read() feed_urls = parse_opml(opml_text)[: args.max_feeds] ``` Every URL extracted from the OPML document is subsequently fetched: ```python def work(url: str) -> Tuple[str, List[Entry], Optional[str]]: try: text = fetch_text(url, timeout=args.timeout) es = parse_feed(url, text) return url, es, None except Exception as e: return url, [], str(e) ``` ### Technical Analysis The Skill legitimately requires outbound network access to retrieve an OPML subscription list and its RSS or Atom feeds. However, the implementation grants substantially broader network access than this functionality requires. Both the user-supplied `--opml-url` and every `xmlUrl` extracted from an OPML document are passed directly to `urllib.request.urlopen`. The implementation does not: - Restrict requests to HTTP or HTTPS. - Require encrypted HTTPS transport. - Reject URLs containing embedded credentials. - Block loopback, private, link-local, multicast, reserved, or cloud metadata IP addresses. - Revalidate hostnames after DNS resolution. - Validate redirect destinations. - Restrict feed retrieval to trusted domains. - Exp ...[truncated 2336 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only `https` URLs for remote OPML and feed retrieval. Explicitly reject `file`, `ftp`, `data`, and all other schemes. 2. Reject URLs containing usernames, passwords, malformed hosts, or ambiguous numeric IP representations. 3. Resolve the hostname before connecting and reject every resolved address belonging to loopback, private, link-local, multicast, unspecified, reserved, or documentation ranges. 4. Explicitly block cloud metadata destinations, including link-local metadata addresses and provider-specific metadata hostnames. 5. Disable automatic redirects or validate every redirect target using the same scheme, hostname, DNS, and IP controls. 6. Protect against DNS rebinding by ensuring the validated address is the address used for the connection, or by using a hardened outbound proxy. 7. Where practical, enforce a domain allowlist for the initial OPML source and expected feed domains. 8. Run the Skill in a sandbox with no access to sensitive local files, cloud metadata services, or internal administrative networks. 9. Record rejected destinations and validation failures without exposing sensitive response content. 10. Apply the same validation function to both `--opml-url` and every URL extracted from OPML. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_brief.py:18
Finding
Unbounded Concurrent Response Processing Enables Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_brief.py`, lines 18–23 and 338–343 **Vulnerability Type**: Unbounded network response buffering and XML processing **Risk Level**: Medium ### Vulnerable Code ```python def fetch_text(url: str, timeout: int) -> str: req = urllib.request.Request(url, headers={"User-Agent": "openclaw-hn-rss-brief/1.0"}) with urllib.request.urlopen(req, timeout=timeout) as r: charset = r.headers.get_content_charset() or "utf-8" return r.read().decode(charset, errors="replace") ``` Multiple responses may be fetched and buffered concurrently: ```python with concurrent.futures.ThreadPoolExecutor(max_workers=max(1, args.workers)) as ex: futures = [ex.submit(work, u) for u in feed_urls] for fu in concurrent.futures.as_completed(futures): _, entries, _ = fu.result() all_entries.extend(entries) ``` ### Technical Analysis `r.read()` reads the complete response body into memory without enforcing a maximum compressed size, decompressed size, or decoded character count. The resulting text is then passed to the XML parser. The user can also control `--workers` and `--max-feeds`. Although the documented defaults are 10 workers and 200 feeds, the code does not impose secure upper bounds. Multiple large or slow responses can therefore be processed concurrently. The configured timeout limits individual blocking operations but does not provide: - A maximum response-body size. - An aggregate download budget. - A total execution deadline. - A maximum decompressed response size. - A maximum XML element or entry count. - A safe upper bound on worker or feed counts. Consequently, malicious or unexpectedly large feed servers can consume excessive memory, CPU, network bandwidth, file descriptors, or execution time. ### Attack Path 1. An attacker controls an OPML document or one or more feed URLs listed in it. 2. The attacker-operated feed endpoints return very large response b ...[truncated 1196 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Read response bodies incrementally and stop when a strict per-response byte limit is reached. 2. Enforce limits on both transferred bytes and decompressed bytes. 3. Reject responses whose declared `Content-Length` exceeds the configured limit, while still enforcing the streaming limit when the header is absent or false. 4. Apply an aggregate byte budget across the entire Skill run. 5. Set secure hard maximums for `--workers`, `--max-feeds`, timeout values, XML element counts, and accepted entries per feed. 6. Add a total execution deadline rather than relying only on per-operation socket timeouts. 7. Validate response media types and reject content that is not an expected XML feed format. 8. Parse XML incrementally where feasible and abort when structural limits are exceeded. 9. Avoid retaining unnecessary full response bodies and entries in memory. 10. Run feed processing with operating-system or container resource limits covering memory, CPU, network use, and open file descriptors. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • 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)

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The description requires the skill to "generate a Chinese categorized brief," which imposes a specific language on all outputs. This is a natural-language policy concern because the file does not indicate any user opt-in, alternative language support, or region-specific justification for the restriction.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The constraint states that each item must be "a Chinese content summary" and forbids embedded English sentences, which hard-codes a language requirement. Because no opt-in or alternative locale handling is described, this appears to violate the policy against forcing a specific language without user choice.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
Multiple strings and the core brief-generation function explicitly produce Chinese summaries and describe the tool as generating a Chinese brief. This is a natural-language locale constraint with no option for the user to select another language or opt in to Chinese output.

Missing User Warnings

Low
Confidence
85% confidence
Finding
This code fetches data from a user-supplied OPML URL and then requests every feed URL listed within it, which transmits system network activity to external hosts. While the behavior is central to the script's purpose, there is no user-facing print, warning, or comment disclosing that remote URLs from the OPML will be contacted.

Static analysis

No suspicious patterns detected.