Back to skill

Security audit

Prompt Gen Skill

Security checks for vulnerabilities and agentic risk

Overview

This skill discloses paid SkillPay use, but it ships broken executable code, an exposed payment API key, and underdocumented external sharing of user identifiers.

Review this before installing. The skill is intended to generate image prompts and charges per call, but it contains a hard-coded payment API key, sends the provided user_id to SkillPay, and currently cannot run because of a Python indentation error. Do not use it with personal identifiers as user_id, and the publisher should remove the exposed key, document the billing data flow, and fail closed when payment cannot be verified.

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

T09 · Insecure Skill Coding Practices

Error
Location
handler.py:11
Finding
Hard-Coded SkillPay API Credential Exposed in Source and Documentation<![CDATA[ ## Vulnerability Details **File Location**: `handler.py:11` and `SKILL.md:24` **Vulnerability Type**: Hard-coded secret exposure **Risk Level**: High ### Vulnerable Code `handler.py:11`: ```python SKILLPAY_API_KEY = "sk_93c5ff38cc3e6112623d361fffcc5d1eb1b5844eac9c40043b57c0e08f91430e" ``` `SKILL.md:24`: ```markdown - API Key: sk_93c5ff38cc3e6112623d361fffcc5d1eb1b5844eac9c40043b57c0e08f91430e ``` The credential is subsequently included in both the request payload and HTTP header in `handler.py:41-48`: ```python payload = { "api_key": SKILLPAY_API_KEY, "user_id": user_id, "amount": PRICE_USDT, "skill_id": SKILL_ID, "currency": "USDT", "description": "AI prompt generation" } headers = {"Content-Type": "application/json", "X-API-Key": SKILLPAY_API_KEY} response = requests.post(f"{SKILLPAY_API_URL}/charge", json=payload, headers=headers, timeout=10) ``` ### Technical Analysis A service credential is embedded directly in executable source code and public-facing Skill documentation. Anyone who can read or obtain the project package can extract the credential without needing runtime access. If the credential remains active, its holder may be able to authenticate directly to the SkillPay API. The precise operations available depend on the server-side permissions assigned to the key. Sending the same secret in both the JSON body and the `X-API-Key` header also unnecessarily duplicates sensitive data in locations that may be captured by application, proxy, or request-body logs. ### Attack Path 1. An attacker downloads, reads, or otherwise obtains the Skill package. 2. The attacker extracts the API key from `SKILL.md` or `handler.py`. 3. The attacker constructs direct requests to the SkillPay API using the exposed key. 4. If the key is active and sufficiently privileged, the attacker performs API operations under the credential owner's identity. 5. Resulting requests may consume quotas, create unauthorized billing activity, or obsc ...[truncated 377 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Revoke and rotate the exposed API key immediately; removing it from the current files does not invalidate copies in package archives or version-control history. 2. Remove the key from both `handler.py` and `SKILL.md`. 3. Load the replacement credential from an environment variable or managed secret store. 4. Abort startup when the required secret is absent rather than using a built-in default. 5. Restrict the replacement key to the minimum required operations, account, and transaction limits. 6. Apply server-side rate limiting and monitor the account for use of the compromised credential. 7. Avoid placing credentials in request bodies when header-based authentication is supported. 8. Add secret-scanning checks to CI and pre-commit workflows. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
handler.py:39
Finding
Billing Exceptions Fail Open and Grant Paid Functionality<![CDATA[ ## Vulnerability Details **File Location**: `handler.py:39-54` and `handler.py:102-120` **Vulnerability Type**: Fail-open payment authorization **Risk Level**: High ### Vulnerable Code `handler.py:39-54`: ```python def charge_user(user_id: str) -> dict: """Charge user via SkillPay""" try: payload = { "api_key": SKILLPAY_API_KEY, "user_id": user_id, "amount": PRICE_USDT, "skill_id": SKILL_ID, "currency": "USDT", "description": "AI prompt generation" } headers = {"Content-Type": "application/json", "X-API-Key": SKILLPAY_API_KEY} response = requests.post(f"{SKILLPAY_API_URL}/charge", json=payload, headers=headers, timeout=10) if response.status_code == 200: return {"success": True, "data": response.json()} return {"success": False, "error": response.text} except Exception as e: return {"success": True, "demo": True, "error": str(e)} ``` The result is trusted by the payment gate in `handler.py:108-120`: ```python charge_result = charge_user(user_id) if not charge_result.get("success") and not charge_result.get("demo"): return { "payment_required": True, "amount": PRICE_USDT, "skill_id": SKILL_ID, "payment_url": charge_result.get("payment_url", "https://skillpay.me") } result = generate_prompt(subject) result["payment_status"] = "free_demo" if charge_result.get("demo") else "paid" return result ``` ### Technical Analysis The broad exception handler converts every billing exception into: ```python {"success": True, "demo": True, ...} ``` This conflates billing failure with successful authorization. Programming defects, DNS failures, connection errors, timeouts, TLS errors, malformed responses, and missing configuration therefore grant access instead of denying it. The subsequent condition accepts either `success` or `demo`. Because the exception path sets both `success=True ...[truncated 1233 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Return `success=False` for every billing exception. 2. Require an explicit, validated payment confirmation before executing paid functionality. 3. Implement demo access as a separate, trusted configuration or entitlement rather than deriving it from an error. 4. Distinguish payment denial, transient service failure, invalid configuration, and application defects. 5. Return a controlled service-unavailable or payment-verification error when billing cannot be confirmed. 6. Log internal exceptions securely, but do not expose raw exception text to callers. 7. Add tests proving that timeouts, DNS failures, missing configuration, malformed responses, and non-200 responses all fail closed. 8. Consider idempotency keys and server-side transaction verification to prevent duplicate or ambiguous charges. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
handler.py:44
Finding
Undefined SKILL_ID Causes Predictable Billing Bypass<![CDATA[ ## Vulnerability Details **File Location**: `handler.py:44` and `handler.py:113` **Vulnerability Type**: Missing security-critical configuration and payment bypass **Risk Level**: High ### Vulnerable Code `handler.py:41-46`: ```python payload = { "api_key": SKILLPAY_API_KEY, "user_id": user_id, "amount": PRICE_USDT, "skill_id": SKILL_ID, "currency": "USDT", "description": "AI prompt generation" } ``` `handler.py:109-114`: ```python if not charge_result.get("success") and not charge_result.get("demo"): return { "payment_required": True, "amount": PRICE_USDT, "skill_id": SKILL_ID, "payment_url": charge_result.get("payment_url", "https://skillpay.me") } ``` No definition of `SKILL_ID` exists in the reviewed project. ### Technical Analysis Evaluating `SKILL_ID` in `charge_user` raises a Python `NameError` before the HTTP request is sent. The surrounding broad exception handler catches that error and marks it as successful demo access. Consequently, once the separate indentation error is corrected, every normal billing attempt follows the free-demo path. The second use of `SKILL_ID` can also raise `NameError` while constructing a payment-required response if execution reaches that branch. Security-critical configuration is therefore neither defined nor validated before request handling. ### Attack Path 1. The syntax error in the file is corrected so the module can run. 2. A caller invokes `handle` with any valid subject. 3. `charge_user` attempts to evaluate the undefined `SKILL_ID`. 4. Python raises `NameError` before any charge request is made. 5. The exception handler returns `success=True` and `demo=True`. 6. `handle` generates and returns the paid output without charging the caller. No special privileges or complex input are required. ### Impact Assessment Billing is predictably nonfunctional, and every valid caller can bypass the advertised payment requirement. The scope is all calls pr ...[truncated 189 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define `SKILL_ID` using trusted deployment configuration. 2. Validate `SKILL_ID`, the API key, API URL, currency, and price during application startup. 3. Refuse to start or refuse paid requests when required billing configuration is missing. 4. Do not convert configuration defects into demo authorization. 5. Add unit tests asserting that missing or invalid `SKILL_ID` values block execution. 6. Add an integration test that confirms a successful billing request contains the expected skill identifier and receives a verifiable transaction result. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
handler.py:41
Finding
Indentation Error Prevents the Skill from Executing<![CDATA[ ## Vulnerability Details **File Location**: `handler.py:41-48` **Vulnerability Type**: Availability failure caused by invalid Python syntax **Risk Level**: Medium ### Vulnerable Code ```python payload = { "api_key": SKILLPAY_API_KEY, "user_id": user_id, "amount": PRICE_USDT, "skill_id": SKILL_ID, "currency": "USDT", "description": "AI prompt generation" } headers = {"Content-Type": "application/json", "X-API-Key": SKILLPAY_API_KEY} response = requests.post(f"{SKILLPAY_API_URL}/charge", json=payload, headers=headers, timeout=10) ``` ### Technical Analysis The `headers` assignment is indented more deeply than the preceding assignment even though no new block was opened. Python therefore raises an `IndentationError` while parsing the module. This is a pre-execution failure: neither the handler, billing function, nor local prompt generator can be imported or invoked. Although this is primarily an availability and quality defect rather than an attacker-driven privilege escalation, it prevents the Skill from providing its documented functionality. ### Attack Path 1. A user, runtime, or orchestration system imports or executes `handler.py`. 2. The Python parser reaches the incorrectly indented `headers` assignment. 3. Parsing terminates with `IndentationError`. 4. The Skill fails before any request can be processed. No attacker-controlled input is required. ### Impact Assessment The defect causes complete denial of service for the Skill in its current state. It does not grant additional privileges or expose system resources, but it prevents all documented prompt-generation and billing functionality. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Align the `headers` assignment with the `payload` and `response` assignments inside the `try` block. 2. Run `python -m py_compile handler.py` as part of CI. 3. Add linting and formatting checks, such as Ruff, Flake8, or Black. 4. Add a smoke test that imports the module and invokes `handle` with representative input. 5. After correcting the syntax, separately remediate the undefined `SKILL_ID` and fail-open billing behavior; fixing indentation alone exposes the payment bypass described in the other findings. ]]>

other

Note
Location
handler.py:41
Finding
User Identifiers Are Disclosed to an External Billing Service Without Adequate Privacy Documentation<![CDATA[ ## Vulnerability Details **File Location**: `handler.py:41-49` and `SKILL.md:19-25` **Vulnerability Type**: External disclosure of caller-provided identifiers **Risk Level**: Low ### Vulnerable Code `handler.py:41-49`: ```python payload = { "api_key": SKILLPAY_API_KEY, "user_id": user_id, "amount": PRICE_USDT, "skill_id": SKILL_ID, "currency": "USDT", "description": "AI prompt generation" } headers = {"Content-Type": "application/json", "X-API-Key": SKILLPAY_API_KEY} response = requests.post(f"{SKILLPAY_API_URL}/charge", json=payload, headers=headers, timeout=10) ``` The documentation only provides the following integration information in `SKILL.md:19-25`: ```markdown ## Integration - API Key: sk_93c5ff38cc3e6112623d361fffcc5d1eb1b5844eac9c40043b57c0e08f91430e - Price: 0.001 USDT per call ``` ### Technical Analysis The caller-provided `user_id` is sent to `https://skillpay.me` as part of the billing payload. The handler does not constrain or pseudonymize this value, so callers or integrating platforms may supply email addresses, platform account identifiers, or other directly identifying values. While the documentation states that payment uses SkillPay, it does not explicitly describe the disclosure of user identifiers, accepted identifier formats, retention practices, or relevant privacy terms. This creates a privacy and data-minimization concern rather than evidence of malicious exfiltration. ### Attack Path 1. A platform or caller invokes `handle` with a personally identifying or externally correlatable `user_id`. 2. `charge_user` copies that value into the billing payload. 3. The handler transmits the value to the external SkillPay endpoint. 4. The third party may process, log, correlate, or retain the identifier according to controls not described in the project. ### Impact Assessment The external service can receive identifiers associated with users invoking the Skill. Depending on the value supplied, this may ...[truncated 232 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Clearly disclose that user identifiers are transmitted to SkillPay for billing. 2. Define and validate the permitted identifier format. 3. Use a stable pseudonymous billing identifier instead of email addresses, usernames, or raw platform account IDs. 4. Transmit only data required to complete the transaction. 5. Document the third party's privacy policy, retention period, and processing purpose. 6. Obtain any consent required by the applicable deployment context and privacy regulations. 7. Prevent secrets or unnecessary personal information from being supplied in the `user_id` field. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (4)

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
This skill is presented as an AI art prompt generator, but it contains billing and outbound payment functionality that is unrelated to the core prompt-generation task. In agent ecosystems, hidden monetization or charging behavior is dangerous because it can trigger unauthorized transactions, create financial risk, and expand the attack surface through external API calls and embedded payment credentials.

Intent-Code Divergence

Medium
Confidence
99% confidence
Finding
The exception path in charge_user returns success=True with demo=True even when charging fails, which causes the rest of the flow to proceed as though charging was acceptable. This creates inconsistent billing behavior, can bypass monetization controls, and makes failures indistinguishable from legitimate free access, undermining auditability and policy enforcement.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code sends user_id to an external billing service without any visible disclosure, consent flow, or minimization. Even if user_id is not highly sensitive by itself, transmitting identifiers to third parties without transparency creates privacy and compliance risks and may enable cross-service tracking.

External Transmission

Medium
Category
Data Exfiltration
Content
"description": "AI prompt generation"
        }
            headers = {"Content-Type": "application/json", "X-API-Key": SKILLPAY_API_KEY}
        response = requests.post(f"{SKILLPAY_API_URL}/charge", json=payload, headers=headers, timeout=10)
        if response.status_code == 200:
            return {"success": True, "data": response.json()}
        return {"success": False, "error": response.text}
Confidence
93% confidence
Finding
This code performs an outbound POST request to an external service from within a skill that appears to only generate local text prompts. In this context, the transmission is more dangerous because it is not necessary for core functionality, sends user-related data off-platform, and uses embedded credentials to interact with a remote billing endpoint.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
handler.py:12

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
SKILL.md:24