Back to skill

Security audit

Ask Leonidas — LEONIDAS Prompt Generator

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real Ask Leonidas prompt generator, but it needs review because its scripts can send your API key and prompt details to any API base URL set in the environment and may open that URL in a browser on failure.

Install only if you intend to use the Ask Leonidas external service and are comfortable sending prompt-related business context to it. Set ASK_LEONIDAS_API_BASE exactly to https://askleonidas.com, avoid putting secrets, customer data, regulated data, or highly confidential business details in pain points, and prefer a version that validates the API host and asks before browser fallback.

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
ask_leonidas.py:43
Finding
Unrestricted API Base Can Disclose Bearer Credentials and User Data<![CDATA[ ## Vulnerability Details **File Location**: `ask_leonidas.py:43-54, 99-112`; `healthcheck.py:14-32` **Vulnerability Type**: Unvalidated network destination with sensitive credential transmission **Risk Level**: High ### Vulnerable Code #### `ask_leonidas.py:43-54` ```python def request_json(url: str, payload: Dict[str, Any], api_key: str, timeout_seconds: int) -> Dict[str, Any]: req = urllib.request.Request( url, data=json.dumps(payload).encode("utf-8"), headers={ "Content-Type": "application/json", "Authorization": f"Bearer {api_key}", "X-Client": "openclaw", }, method="POST", ) with urllib.request.urlopen(req, timeout=timeout_seconds) as resp: return json.loads(resp.read().decode("utf-8")) ``` #### `ask_leonidas.py:99-112` ```python api_base = get_env("ASK_LEONIDAS_API_BASE", "").rstrip("/") api_key = get_env("ASK_LEONIDAS_API_KEY", "") timeout = int(get_env("ASK_LEONIDAS_TIMEOUT_SECONDS", str(DEFAULT_TIMEOUT))) if not api_base: print(json.dumps({"error": "ASK_LEONIDAS_API_BASE is not set."}, ensure_ascii=False)) return 1 if not api_key: print(json.dumps({"error": "ASK_LEONIDAS_API_KEY is not set."}, ensure_ascii=False)) return 1 url = api_base + "/api/v1/openclaw/generate" payload = build_payload(args) ``` #### `healthcheck.py:14-32` ```python api_base = os.environ.get("ASK_LEONIDAS_API_BASE", "").rstrip("/") api_key = os.environ.get("ASK_LEONIDAS_API_KEY", "") timeout = int(os.environ.get("ASK_LEONIDAS_TIMEOUT_SECONDS", str(DEFAULT_TIMEOUT))) if not api_base: print(json.dumps({"error": "ASK_LEONIDAS_API_BASE is not set."}, ensure_ascii=False)) return 1 if not api_key: print(json.dumps({"error": "ASK_LEONIDAS_API_KEY is not set."}, ensure_ascii=False)) return 1 req = urllib.request.Request( api_base + "/api/v1/openclaw/he ...[truncated 3691 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Use a fixed production endpoint by default** Define the trusted service endpoint in code instead of requiring a configurable production base: ```python DEFAULT_API_BASE = "https://askleonidas.com" api_base = get_env("ASK_LEONIDAS_API_BASE", DEFAULT_API_BASE) ``` 2. **Validate the URL before attaching credentials** Parse the URL with `urllib.parse.urlparse` and require: - Scheme exactly equal to `https` - Hostname exactly equal to `askleonidas.com` - No embedded username or password - No unexpected port - No malformed or ambiguous hostname Example: ```python from urllib.parse import urlparse TRUSTED_HOST = "askleonidas.com" def validate_api_base(value: str) -> str: parsed = urlparse(value) if parsed.scheme != "https": raise ValueError("ASK_LEONIDAS_API_BASE must use HTTPS.") if parsed.hostname != TRUSTED_HOST: raise ValueError("ASK_LEONIDAS_API_BASE must target askleonidas.com.") if parsed.username or parsed.password: raise ValueError("Embedded URL credentials are not allowed.") if parsed.port not in (None, 443): raise ValueError("Unexpected API port.") return "https://askleonidas.com" ``` 3. **Apply identical validation in every client** Centralize endpoint and credential handling in one shared function used by both `ask_leonidas.py` and `healthcheck.py`. This prevents the health check from becoming a less-protected credential disclosure path. 4. **Separate development endpoint support** If custom endpoints are required for local development, require an explicit development flag and use a separate non-production credential. Never transmit a live production key to a custom host. 5. **Constrain browser fallback** Open only the fixed trusted URL: ```python webbrowser.open("https://askleonidas.com/openclaw") ``` Do not derive the browser destination from a ...[truncated 618 chars]
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (11)

Tainted flow: 'req' from os.environ.get (line 25, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
)

    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            raw = resp.read().decode("utf-8")
            print(raw if raw.strip() else json.dumps({"status": "empty"}))
            return 0
Confidence
93% confidence
Finding
The request URL is built from the ASK_LEONIDAS_API_BASE environment variable and then used directly in urllib.request.urlopen, creating a server-side request forgery style sink if an attacker can influence environment configuration. In an agent/skill context, this can exfiltrate the bearer API key to an attacker-controlled host via the Authorization header and allow unexpected outbound network access, which makes the issue more dangerous than a simple health check misconfiguration.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The documented behavior promises broad prompt generation and inference, while the observed behavior reportedly only performs service health/status checking with credentials and network access. This mismatch is dangerous because users may authorize the skill based on benign expectations while it actually exercises external access for a different purpose, undermining informed consent and trust boundaries.

Credential Access

High
Category
Privilege Escalation
Content
# Ask Leonidas OpenClaw Skill — Environment Setup
# Copy these lines into your shell profile or a .env file.
# Get your API key at https://askleonidas.com

# Required
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill requires network access and API-key-backed environment variables but does not declare any explicit tool scope or allowed-tools boundary. That weakens least-privilege controls and makes it harder for users or the platform to understand that sensitive data and external connectivity are required before activation.

Vague Triggers

Medium
Confidence
87% confidence
Finding
Claiming applicability to 'any professional pain point' and 'any workflow' creates unclear activation boundaries and encourages excessive scope. In context, this is more dangerous because the skill sends user-provided content to an external API, so vague scope increases the chance of unnecessary or inappropriate data transmission.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The trigger phrases are broad enough to match common user requests such as generic prompt-writing help. Overbroad activation can cause the skill to capture conversations unintentionally and route user content to an external service when the user did not specifically request that integration.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill instructs the agent to transmit user-provided pain points to an external API, and potentially via browser automation, without a user-facing disclosure or consent step. Professional pain points can contain confidential business, personnel, customer, or regulated information, so silent exfiltration to a third party poses a real privacy and compliance risk.

Behavior Manipulation

Medium
Category
Prompt Injection
Content
- Surface the exact error message returned by the API.
- If both the API and browser fallback fail, tell the user clearly and suggest they visit `https://askleonidas.com` directly.
- Never expose the API key in any output.
- Always prefer the API path over browser automation.

## Rate limits
Confidence
70% confidence
Finding
Subtle instructions detected that may alter agent decision-making or introduce hidden biases.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The script sends fields such as pain point, role, industry, desired outcome, locale, and user tier to a remote endpoint using an authenticated HTTP POST request. While network transmission is core to the tool's purpose, the code provides no explicit user-facing warning that these inputs are sent to an external service.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The code opens a local web browser on any general exception, even though browser interaction is not necessary for prompt generation. This creates unexpected side effects from a non-interactive CLI tool and can drive the user to a remote site after unrelated failures, increasing phishing, tracking, or unsafe-navigation risk if the API base is misconfigured or attacker-controlled.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The browser fallback is triggered automatically without prior notice or consent from the user. Unexpectedly launching a browser can expose users to untrusted content, leak context to the desktop/browser environment, and violate least surprise for automation contexts where this skill should only emit structured output.

Static analysis

No suspicious patterns detected.