Back to skill

Security audit

SEO Analyzer Pro

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent SEO analyzer, but it exposes a credential-like API key and fetches arbitrary user-supplied URLs without clear safeguards.

Review carefully before installing. Only analyze public URLs, avoid internal or sensitive links, and require the publisher to remove and rotate the exposed API key and add URL validation that blocks private, localhost, link-local, and redirected internal destinations.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
handler.py:5
Finding
Unrestricted Server-Side Request Forgery Through User-Controlled URLs<![CDATA[ ## Vulnerability Details **File Location**: `handler.py:5, 25-27` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```python def analyze_seo(url: str) -> dict: try: resp = requests.get(url, timeout=10) ``` ```python def handle(input_text: str, user_id: str = "default") -> dict: url = re.search(r'https?://[^\s]+', input_text) if not url: return {"error": "Please provide a URL"} return analyze_seo(url.group(0)) ``` ### Technical Analysis The handler extracts an arbitrary HTTP or HTTPS URL from attacker-controlled input and passes it directly to `requests.get()`. It does not validate the destination hostname, resolved IP address, network range, port, or redirect chain. The timeout only limits request duration; it does not prevent access to loopback addresses, private networks, link-local services, cloud metadata endpoints, or other resources reachable from the execution environment. Because redirects are followed by `requests` by default, checking only the initial URL would also be insufficient. The implementation reads the full response body through `resp.text` without imposing a maximum response size. This creates an additional resource-exhaustion risk when a remote server returns an excessively large response. ### Attack Path 1. An attacker submits an SEO request containing a URL that targets an internal or privileged endpoint, such as a loopback address, RFC 1918 address, or link-local cloud metadata service. 2. `handle()` accepts the URL because it only verifies that the string begins with `http://` or `https://`. 3. `analyze_seo()` causes the Skill host to issue the request from its own network context. 4. The target response is loaded into memory and parsed. 5. Extracted title, description, and heading data—or network and application details contained in returned errors—may be exposed to the attacker. 6. The attacker can repeat the process against different hosts ...[truncated 1063 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Permit only destinations required for the Skill's legitimate operation; an explicit hostname allowlist is preferable. - Resolve the hostname before connecting and reject loopback, private, link-local, multicast, unspecified, reserved, and other non-public IP ranges for both IPv4 and IPv6. - Protect against DNS rebinding by ensuring that the validated address is the address actually used for the connection. - Restrict allowed schemes to HTTPS where possible and reject embedded credentials or nonstandard ports unless specifically required. - Disable redirects, or validate the scheme, hostname, port, and resolved IP address of every redirect target before following it. - Enforce outbound firewall or proxy rules that prevent access to internal networks and cloud metadata addresses. - Stream responses and stop reading after a conservative maximum byte limit. - Validate the response content type before parsing it as HTML. - Use separate connection and read timeouts and impose limits on redirect count. - Return generic errors to users rather than raw exception strings that may disclose internal network details. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:48
Finding
Plaintext Hard-Coded API Credential in Skill Documentation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:48` **Vulnerability Type**: Hard-Coded Secret **Risk Level**: High ### Vulnerable Code ```markdown ## Integration - API Key: sk_93c5ff38cc3e6112623d361fffcc5d1eb1b5844eac9c40043b57c0e08f91430e - Price: 0.001 USDT per call ``` ### Technical Analysis The Skill documentation contains a plaintext value explicitly identified as an API key. Anyone who can read the package, repository, build artifact, logs containing the file, or repository history can recover the credential. The Python implementation does not reference this key, so the audit cannot establish which external service accepts it or whether it remains active. Nevertheless, committing a credential in distributable documentation exposes it outside an appropriate secret-management boundary. Removing the key only from the current file is insufficient if it has already been committed or distributed, because it may remain available in source-control history, caches, package archives, and downstream copies. ### Attack Path 1. An attacker obtains access to the Skill package or its source repository. 2. The attacker reads `SKILL.md` and copies the exposed API key. 3. The attacker identifies or already knows the associated API service. 4. If the key remains valid, the attacker authenticates to that service as the credential owner. 5. The attacker consumes available quota or performs any actions authorized to the key until it is revoked or otherwise restricted. ### Impact Assessment If active, the credential may enable unauthorized API calls, quota consumption, financial charges, service abuse, or impersonation of the credential owner. The precise scope depends on the unknown service and permissions assigned to the key. No evidence in the audited implementation establishes broader system compromise, and the key is not used by `handler.py`. The confirmed issue is the plaintext exposure of a credential-like value and the resulting possibility ...[truncated 27 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Revoke and rotate the exposed key immediately; do not rely solely on deleting it from the current file. - Search source-control history, release artifacts, caches, logs, and package registries for additional copies. - Remove the credential from documentation and replace it with an unmistakable placeholder such as `YOUR_API_KEY`. - Store operational credentials in a dedicated secret manager or protected environment variable. - Grant replacement credentials only the minimum permissions and quota required. - Apply service-side restrictions such as endpoint scope, source restrictions, expiration, and spending limits where supported. - Enable secret scanning in version control and CI pipelines to block future credential commits. - Review service audit logs for use of the exposed key and investigate any unrecognized activity. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The skill embeds a live-looking API key directly in the markdown, which exposes a credential to anyone who can view or copy the skill. In this context, an SEO analyzer does not need to disclose raw secrets in its public description, so the key is an unjustified capability that could enable unauthorized API use, billing abuse, or pivoting into connected services.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The usage section lists example invocations like "Check SEO score of my website" and "SEO analysis for [URL]" but does not define whether these are the only triggers, what input formats are required, or any exclusion conditions. This ambiguity could cause unintended invocation because the phrases are general and there are no negative examples or scope limits.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The skill indicates an external integration and accepts user-supplied URLs, but it does not warn users that submitted URLs may be sent to third-party services or fetched externally. In a URL-analysis context, that omission matters because users may unknowingly disclose internal, private, or sensitive links, and external fetching can create privacy and SSRF-like risk depending on implementation.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
SKILL.md:48