Back to skill

Security audit

Seo Audit

Security checks for vulnerabilities and agentic risk

Overview

This is a normal SEO audit skill, but its optional script can make unrestricted network requests to any supplied URL without internal-address or response-size limits.

Review before installing in environments with access to internal networks, cloud metadata services, or shared resources. Use it only where outbound requests are sandboxed, and prefer adding URL validation, redirect validation, private-address blocking, and response-size limits before enabling the bundled script.

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/seo_audit.py:97
Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/seo_audit.py:97-103`, `scripts/seo_audit.py:190-195`, and `scripts/seo_audit.py:271-282` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```python def fetch_page(url): req = urllib.request.Request(url, headers={ "User-Agent": "Mozilla/5.0 (compatible; SEOAuditBot/1.0)" }) with urllib.request.urlopen(req, timeout=15) as response: return response.read().decode("utf-8", errors="replace"), response.geturl() ``` ```python def audit_url(url, keywords=None, competitors=None): if not url.startswith("http"): url = "https://" + url html, final_url = fetch_page(url) ``` ```python keywords = [k.strip() for k in args.keywords.split(",") if k.strip()] competitor_urls = [c.strip() for c in args.competitors.split(",") if c.strip()] print(f"Auditing: {args.url}", file=sys.stderr) result = audit_url(args.url, keywords=keywords) competitor_results = [] for comp_url in competitor_urls: print(f"Auditing competitor: {comp_url}", file=sys.stderr) try: comp_result = audit_url(comp_url, keywords=keywords) ``` ### Technical Analysis The primary URL and every competitor URL are attacker-controlled command-line inputs. They flow into `audit_url()` and then into `urllib.request.urlopen()` without validation of the destination host or resolved IP address. The `startswith("http")` condition is not a security control. It neither restricts input to well-formed public HTTP or HTTPS URLs nor rejects loopback, private-network, link-local, reserved, or cloud metadata addresses. `urllib.request.urlopen()` also follows HTTP redirects by default, while the code does not validate redirect destinations. Consequently, the process can be used as a network proxy to issue requests to resources that are reachable from the host running the audit but are not directly reachable by the user. ### Attack Path 1. An attacker sup ...[truncated 1645 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse input with `urllib.parse.urlsplit()` and allow only the exact `http` and `https` schemes. 2. Reject URLs containing credentials, malformed hostnames, ambiguous numeric IP representations, or unsupported ports. 3. Resolve the hostname before connecting and reject every address classified as loopback, private, link-local, multicast, reserved, or unspecified using Python's `ipaddress` module. 4. Protect against DNS rebinding by ensuring the validated address is the address used for the connection, or by applying equivalent outbound controls at the network layer. 5. Disable automatic redirects or implement a restricted redirect handler that repeats scheme, hostname, and resolved-address validation for every redirect target. 6. Consider an explicit allowlist of domains when the deployment has a known set of permitted audit targets. 7. Apply outbound firewall or proxy rules that prevent the process from reaching internal and metadata networks. 8. Return a clear validation error without including sensitive internal response data. A hardened implementation should validate both the original destination and every redirect immediately before the corresponding connection. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/seo_audit.py:97
Finding
Unbounded HTTP Response Download Enables Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/seo_audit.py:97-103` **Vulnerability Type**: Uncontrolled Resource Consumption **Risk Level**: Medium ### Vulnerable Code ```python def fetch_page(url): req = urllib.request.Request(url, headers={ "User-Agent": "Mozilla/5.0 (compatible; SEOAuditBot/1.0)" }) with urllib.request.urlopen(req, timeout=15) as response: return response.read().decode("utf-8", errors="replace"), response.geturl() ``` ### Technical Analysis Calling `response.read()` without a size argument buffers the entire response body in memory. The implementation does not inspect or limit `Content-Length`, does not enforce an accumulated-byte ceiling while reading, and does not restrict accepted content types. The 15-second timeout is not a reliable response-size control. A server can send a very large body within that interval, and timeout behavior does not establish a maximum number of bytes. After download, decoding and HTML parsing create additional memory and CPU overhead. ### Attack Path 1. An attacker supplies an attacker-controlled URL as the audit target or as a competitor. 2. The remote server responds with an extremely large body or a high-volume stream. 3. `fetch_page()` calls `response.read()` without a byte limit and attempts to hold the complete body in memory. 4. The complete body is decoded into a string and passed to `HTMLParser`, increasing memory and CPU consumption. 5. The audit process slows down, becomes unresponsive, raises an out-of-memory exception, or is terminated by the operating system. 6. Repeated audit requests can amplify the availability impact in a service that invokes this script for multiple users. ### Impact Assessment Exploitation can consume memory, CPU time, and network bandwidth under the privileges of the audit process. It can terminate an individual audit, reduce service capacity, or cause denial of service for other users when the script runs inside a sha ...[truncated 256 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define a conservative maximum response size appropriate for HTML audits. 2. Reject responses whose declared `Content-Length` exceeds that limit. 3. Read the body incrementally in fixed-size chunks while tracking the cumulative byte count. 4. Abort the request as soon as the hard byte limit is exceeded; do not rely solely on `Content-Length`, because it may be absent or false. 5. Restrict accepted content types to expected HTML media types, while handling missing or malformed headers safely. 6. Add separate connection and read deadlines where the HTTP client supports them. 7. Apply operating-system or container limits for memory, CPU, execution time, and concurrent audits. 8. Avoid retaining unnecessary copies of the body during decoding and parsing; incremental parsing can further reduce peak memory usage. 9. Return a controlled error when limits are exceeded instead of attempting to parse the partial oversized document. ]]>
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill instructs use of network-capable tools (`web_fetch` and `web_search`) and even references running a local script, but it declares no explicit tool scope or permissions boundary. That increases the chance the agent can perform unintended outbound requests or invoke broader capabilities than the author intended, which matters because the input URL/domain is user-controlled and external content is adversarial.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The manifest says the skill should be used for 'any website or URL' and lists broad triggers such as 'audit my site', 'improve rankings', and 'meta tags'. These phrases are common in ordinary SEO-related conversation and the file does not provide exclusion conditions or tighter activation boundaries, increasing the risk of unintended invocation.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The script performs outbound requests to a fully user-supplied URL using urllib without validation, allowlisting, or any warning that network access will occur. In an agent setting, this creates an SSRF-style risk: an attacker can induce requests to internal services, cloud metadata endpoints, localhost, or other sensitive network locations reachable from the execution environment.

Static analysis

No suspicious patterns detected.