Back to skill

Security audit

Web Site or Domain Name Basic Information Scanner

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent website scanner, but it needs review because scanned sites can steer it into making unintended outbound requests from the user's environment.

Review before installing. Use this only against public or authorized targets, preferably from an isolated environment with restricted egress, because a scanned site can influence follow-up requests through sitemap data. Avoid scanning internal domains or sensitive investigations unless third-party lookups and outbound disclosure are acceptable.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/scan.py:253
Finding
Server-Side Request Forgery Through Unvalidated Sitemap URLs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/scan.py:253-261` and `scripts/scan.py:435-440` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code #### Sitemap URL obtained from robots.txt ```python sitemap_url = f"{parsed.scheme}://{parsed.netloc}/sitemap.xml" response = self.session.get(sitemap_url, timeout=10) if response.status_code != 200: # Try robots.txt to find sitemap robots = self.fetch_robots_txt() sitemap_match = re.search(r'Sitemap:\s*(.+)', robots, re.IGNORECASE) if sitemap_match: sitemap_url = sitemap_match.group(1).strip() response = self.session.get(sitemap_url, timeout=10) ``` #### Page URLs obtained from the sitemap ```python for url_data in urls: url = url_data.get("loc") if not url or url == self.url: continue try: response = analyzer.session.get(url, timeout=15) ``` ### Technical Analysis The scanned website controls both the `Sitemap:` directive returned in `robots.txt` and the URL values contained in the sitemap. The application passes these values directly to `requests.Session.get()` without validating: - The URL scheme. - Whether the destination belongs to the original scanned site. - Whether the resolved address is loopback, private, link-local, reserved, or otherwise internal. - Whether an allowed hostname resolves to a prohibited address. - Redirect destinations and each redirect hop. - Destination ports. The `requests` library follows HTTP redirects by default. Consequently, even an initially acceptable URL can redirect the scanner to an internal destination. Fetching website resources is part of the intended functionality, but allowing a remote website to select arbitrary cross-origin destinations is unnecessary for ordinary same-site analysis. This creates an SSRF primitive in the environment running the scanner. The initial user-supplied target is also fetched without network-range restrictions ...[truncated 2641 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Restrict URL schemes** - Parse every target with `urllib.parse.urlparse()`. - Permit only `http` and `https`. - Reject URLs containing embedded credentials or malformed hostnames. 2. **Enforce an origin policy** - By default, require sitemap and page URLs to use the original scanned hostname or an explicitly approved registrable domain. - If cross-origin sitemaps are required, make that behavior opt-in and apply an explicit allowlist. 3. **Block prohibited network ranges** - Resolve all destination hostnames before connecting. - Reject every resolved IPv4 and IPv6 address classified as loopback, private, link-local, multicast, reserved, unspecified, or otherwise non-global. - Repeat this check immediately before connection to reduce DNS rebinding risk. - Apply the same controls to the initial user-supplied target. 4. **Validate redirects** - Disable automatic redirects with `allow_redirects=False`, or manually follow a small number of redirects. - Reapply scheme, origin, hostname, port, and resolved-address validation to every redirect hop. 5. **Constrain ports and outbound access** - Permit only required destination ports, normally 80 and 443. - Use operating-system, container, or firewall egress controls to prevent access to internal and metadata networks. - Run the scanner in an isolated environment with no access to sensitive internal services. 6. **Limit fetched content** - Stream responses and enforce maximum response sizes. - Set connection and read timeouts separately. - Validate content types before parsing data as HTML or XML. 7. **Add regression tests** - Verify rejection of loopback, RFC1918, link-local, IPv6 local, integer-encoded IP, mixed-notation IP, and redirect-based destinations. - Test cross-origin sitemap directives, DNS rebinding scenarios, and URLs containing user information or unusual ports. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (19)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill clearly instructs use of network access, shell commands, and report output, but it declares no explicit tool scope or permissions boundary. In an agent setting, this can lead to over-broad execution authority, making it easier for the skill to trigger unexpected network calls, shell execution, or file writes without transparent user consent or enforcement.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The description presents comprehensive website scanning and third-party checks without warning that user-supplied domains and page content will be transmitted to external systems such as DNS resolvers, WHOIS servers, websites being scanned, search engines, or optional third-party services. This creates a privacy and operational risk because sensitive targets or investigation intent may be disclosed during scanning.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
### "dig command not found"
```bash
# Ubuntu/Debian
sudo apt-get install dnsutils

# macOS
brew install bind
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
### "dig command not found"
```bash
# Ubuntu/Debian
sudo apt-get install dnsutils

# macOS
brew install bind
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
### "dig command not found"
```bash
# Ubuntu/Debian
sudo apt-get install dnsutils

# macOS
brew install bind
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
for record_type in cls.RECORD_TYPES:
            try:
                result = subprocess.run(
                    ["dig", "+short", "-t", record_type, domain],
                    capture_output=True,
                    text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def query_whois(domain: str) -> Dict:
        """Query WHOIS data for domain"""
        try:
            result = subprocess.run(
                ["whois", domain],
                capture_output=True,
                text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The scanner automatically performs multiple external lookups to third parties and target-controlled endpoints, including ipapi.co, Google, DNS/WHOIS infrastructure, and optionally sitemap-derived pages, without a clear user-facing disclosure or consent boundary. In a security-tool context, this can unintentionally leak the target being investigated, the operator's IP/user agent, and internal or sensitive domains if users scan non-public assets.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest explicitly states that deep scanning supports Playwright for client-side rendered pages, but the deep scan code only performs additional plain HTTP GET requests with requests/BeautifulSoup and extracts static HTML titles. There is no Playwright import, browser automation, or JavaScript-rendered page handling anywhere in this file, so the advertised capability is not actually implemented.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.28.0
beautifulsoup4>=4.11.0
lxml>=4.9.0
reportlab>=3.6.0
Confidence
96% confidence
Finding
The dependency is specified with a lower bound only, which allows future installs to resolve to different versions over time. This weakens reproducibility and can unintentionally introduce vulnerable or breaking releases, especially for a network-facing scanning tool that relies on HTTP functionality.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
93% confidence
Finding
Because requests is not pinned, there is no way to verify from this manifest whether the installed version includes fixes for known advisories. In a website scanning tool that makes outbound HTTP requests, dependency ambiguity increases the chance that a vulnerable build is deployed and exposed to attacker-controlled URLs or responses.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.28.0
beautifulsoup4>=4.11.0
lxml>=4.9.0
reportlab>=3.6.0
Confidence
95% confidence
Finding
Using an unpinned beautifulsoup4 version makes builds non-deterministic and may pull in newer releases without prior testing. While not inherently exploitable by itself, it increases supply-chain and stability risk for the skill's web-content parsing functionality.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.28.0
beautifulsoup4>=4.11.0
lxml>=4.9.0
reportlab>=3.6.0
Confidence
98% confidence
Finding
lxml is unpinned even though it is a complex parser with a history of security advisories. In a website scanning skill that parses remote HTML/XML content, allowing arbitrary future versions increases the chance of introducing parser-related vulnerabilities or regressions into production.

Unverifiable Dependency: lxml has 14 known advisory(ies) (CVE-2021-43818 (lxml's HTML Cleaner allows crafted and SVG embedded scripts to pass through); CVE-2014-3146 (lxml Cross-site Scripting Via Control Characters); CVE-2021-28957 (lxml vulnerable to Cross-Site Scripting ) +11 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
97% confidence
Finding
The manifest does not prove which lxml release will be installed, despite lxml having multiple historical advisories. Given this skill parses remote website content, any unresolved parser or sanitizer flaws in the installed version could become reachable through attacker-supplied HTML/XML data.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.28.0
beautifulsoup4>=4.11.0
lxml>=4.9.0
reportlab>=3.6.0
Confidence
98% confidence
Finding
reportlab is specified with only a minimum version, so installs may resolve to unknown releases, including ones with security issues. This is more concerning because reportlab has had high-impact bugs historically, and PDF/report generation often processes untrusted content gathered from scanned websites.

Unverifiable Dependency: reportlab has 8 known advisory(ies) (CVE-2023-33733 (Reportlab vulnerable to remote code execution); CVE-2020-28463 (Server-side Request Forgery (SSRF) via img tags in reportlab); CVE-2019-19450 (ReportLab vulnerable to remote code execution via paraparser) +5 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
98% confidence
Finding
reportlab has known high-impact advisories, and the unpinned requirement means the deployed version cannot be verified as safe. This matters more in this skill because scanned website content may later be embedded into generated reports, potentially exposing PDF generation paths to untrusted input.

Intent-Code Divergence

Low
Confidence
81% confidence
Finding
The function documentation suggests a straightforward WHOIS query, but the implementation parses and returns specific registrant organization and country fields in addition to basic domain data. While related to WHOIS, the docstring understates the collection of registrant-identifying information.

Intent-Code Divergence

Low
Confidence
93% confidence
Finding
The docstrings for fetch_robots_txt and fetch_llms_txt say 'Fetch and parse', which implies structured interpretation of these files. In reality, both functions only download the file and return raw text slices or status strings, with no parsing logic beyond simple retrieval.

Missing User Warnings

Low
Confidence
89% confidence
Finding
The JSON report function writes directly to a user-supplied filename, and the PDF report function likewise creates output files, but there is no confirmation prompt or warning that existing files may be overwritten. The operation is not destructive in a severe sense, but it is a file write affecting local user data without clear disclosure at the point of action.

Static analysis

No suspicious patterns detected.