Back to skill

Security audit

TopHotCN

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent TopHub scraping tool, but its article fetcher can browse any URL from local JSON files without validation, which needs careful review before use.

Install and run this only in an isolated environment or network context where browser requests cannot reach sensitive internal services. Use it on trusted TopHub-generated JSON files, prefer --output to avoid modifying originals, and consider pinning dependencies before installation.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/fetch_site_content.py:27
Finding
Unvalidated URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch_site_content.py`, lines 27–35 and 82–98 **Vulnerability Type**: Server-Side Request Forgery (SSRF) through an unrestricted browser crawler **Risk Level**: High ### Vulnerable Code The crawler accepts an arbitrary URL and navigates to it without validating its scheme, hostname, resolved IP address, or redirect destination: ```python async def _fetch_with_crawl4ai(url): """Use crawl4ai to fetch the page asynchronously.""" from crawl4ai import AsyncWebCrawler, CrawlerRunConfig config = CrawlerRunConfig(magic=True) async with AsyncWebCrawler() as crawler: result = await crawler.arun(url=url, config=config) if result.success: return {'url': url, 'content': result.markdown, 'error': None} else: return {'url': url, 'content': '', 'error': result.error_message} ``` The URL originates directly from a supplied JSON file: ```python url = data.get('url', '') title = data.get('title', 'Unknown title') if not url: print(f"Error: file has no URL field: '{filepath}'") return print(f"Fetching: {title}") print(f"URL: {url}") # Fetch content result = fetch_content(url) if result.get('error'): print(f"Fetch failed: {result['error']}") ``` ### Technical Analysis The input JSON file is treated as trusted even though users or other processes can create or modify it. Its `url` field is passed directly to `crawler.arun()`. There are no controls that: - Restrict the URL to HTTP or HTTPS. - Reject embedded credentials or malformed hostnames. - Block loopback, private, link-local, reserved, multicast, or cloud metadata addresses. - Validate DNS resolution results. - Revalidate destinations after redirects. - Restrict requests to hosts obtained through the intended TopHub workflow. Because Crawl4AI operates through a browser, the resulting request originates from the machine running the Sk ...[truncated 1875 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse URLs with a standards-compliant parser and permit only explicit `http` and `https` schemes. 2. Reject URLs containing credentials, ambiguous host representations, malformed ports, or missing hostnames. 3. Resolve every hostname before navigation and reject all resolved loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 addresses. 4. Explicitly block well-known cloud metadata destinations. 5. Revalidate every redirect destination and its resolved addresses before following it. 6. Protect against DNS rebinding by enforcing destination controls at connection time, preferably through an egress proxy or network policy rather than relying only on preflight DNS checks. 7. Consider an allowlist of domains supplied by the trusted TopHub workflow. If arbitrary public websites must remain supported, require explicit user confirmation for hosts outside a trusted set. 8. Run the crawler in a restricted environment with no access to internal networks, metadata services, sensitive local files, or unnecessary credentials. 9. Add tests covering loopback addresses, private IPv4 and IPv6 ranges, encoded IP forms, DNS aliases, redirects to private destinations, and unsupported schemes. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:7
Finding
Unpinned Runtime Dependencies Create a Supply-Chain Exposure<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 7–8 **Vulnerability Type**: Unpinned third-party packages and browser artifacts **Risk Level**: Medium ### Vulnerable Code The documented installation process retrieves mutable package versions and a browser artifact without a lockfile or integrity verification: ```bash pip install crawl4ai requests tqdm pypinyin python -m playwright install chromium ``` ### Technical Analysis No versions or hashes are specified for `crawl4ai`, `requests`, `tqdm`, or `pypinyin`. Consequently, two installations performed at different times can resolve to different dependency graphs. The project also contains no reviewed lockfile or hash manifest in the audited directory. Python packages can run code during installation and subsequently execute with the privileges of the user running the Skill. The Chromium installation is also coupled to whichever Playwright version the environment resolves, rather than to a documented and reviewed version. This does not prove that any currently named dependency is malicious. It creates a supply-chain exposure in which a future compromised release, malicious transitive dependency, or incompatible update could be installed without a corresponding change to the audited project. ### Attack Path 1. A user or Agent follows the setup instructions in `SKILL.md`. 2. The package installer queries its configured package index and resolves the latest versions satisfying unconstrained dependency requirements. 3. A compromised or unexpectedly changed direct or transitive package is selected. 4. Package installation or later import executes package-controlled code with the installing user's privileges. 5. That code can access resources available to the Python process, including project files, user-accessible files, environment variables, and permitted network destinations. The same mutable-resolution issue affects the relationship between Playwright and its downloaded Chromium ar ...[truncated 588 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin exact, reviewed versions of every direct dependency. 2. Generate and commit a dependency lockfile that includes all transitive dependencies. 3. Require cryptographic hashes during installation, such as with a hash-locked requirements file and `pip --require-hashes`. 4. Pin the Playwright package version so its expected Chromium artifact is deterministic and document the corresponding browser revision. 5. Install dependencies in an isolated virtual environment or container under a non-privileged account. 6. Configure an approved package index explicitly and avoid untrusted extra indexes. 7. Use automated dependency vulnerability and provenance scanning, while reviewing lockfile changes before updates. 8. Apply upgrades through controlled pull requests rather than resolving current releases during every Skill installation. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Vague Triggers

Medium
Confidence
90% confidence
Finding
The example trigger phrases are broad, natural-language requests like '帮我获取这篇文章的正文' and '把这个目录下的文章都抓取一下', which can easily overlap with ordinary user requests outside this specific skill. In agent routing systems, this increases the chance of unintended activation, causing the agent to run web-scraping or file-processing actions in the wrong context and potentially touch arbitrary local paths or external URLs supplied indirectly through JSON inputs.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This code file performs HTTP/content retrieval from arbitrary URLs and, by default, writes fetched results back into the original JSON files. While the CLI help mentions that content is fetched and rewritten, it does not clearly warn users that running the script will contact external sites and transmit request metadata to those sites, which is a relevant safety/privacy disclosure for a URL-crawling tool.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The argparse description says '今日热榜爬虫 + 内容抓取', which indicates the tool also fetches content. However, the implemented workflow only fetches ranking entries from tophub.today and writes title/description/url metadata, with content explicitly left empty and a later message directing users to a different script for body fetching.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The natural-language instructions, examples, and operational guidance are presented entirely in Chinese, but the file does not state that the skill is intended only for Chinese-speaking users or provide any language opt-in. This can violate language/locale policy when a skill implicitly forces one language without user choice.

Natural-Language Policy Violations

Low
Confidence
81% confidence
Finding
Natural-language strings in the module docstring and CLI help are exclusively Chinese, and the script does not offer a language or locale choice. Per the policy, forcing a specific language without opt-in is a locale/language policy issue unless explicitly documented and justified.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The HTTP session sets the Accept-Language header to 'zh-CN,zh;q=0.9', which hard-codes a language/locale preference. This is a natural-language locale constraint and the file does not offer user opt-in or explain why a Chinese locale is required.

Static analysis

No suspicious patterns detected.