Back to skill

Security audit

EODHD API

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward EODHD financial-data helper, but users should treat its API-token handling as sensitive.

Install only if you are comfortable providing an EODHD API token. Prefer using a temporary token or environment-based secret handling if possible, restrict config.json permissions if you persist it, and avoid sharing full error objects because they may include the token.

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

Warning
Location
scripts/eodhd_client.py:37
Finding

API Token Disclosed in Error Return Values

Content
View full analysis

Vulnerability Details

File Location: scripts/eodhd_client.py, lines 37-48
Vulnerability Type: Sensitive credential exposure through error handling
Risk Level: Medium

Complete Code Snippet:

python
def _get_request(self, endpoint, params=None):
    '''Helper function to make a GET request to the API.'''
    if params is None:
        params = {}
    params['api_token'] = self.api_token
    params['fmt'] = 'json'
    
    url = f"{self.base_url}/{endpoint}"
    try:
        response = requests.get(url, params=params)
        response.raise_for_status()  # Raise an exception for bad status codes (4xx or 5xx)
        return response.json()
    except requests.exceptions.RequestException as e:
        return {"error": str(e), "url": url, "params": params}

Technical Analysis

The method inserts the EODHD API token into the mutable params dictionary and returns that entire dictionary when a network or HTTP error occurs. Consequently, every returned error object contains the plaintext token under params["api_token"].

The Skill instructions direct callers to check for an error field and report errors to the user. A caller that serializes, prints, logs, or otherwise exposes the complete error object can therefore disclose the credential. Authentication is necessary for the API request, but including the credential in diagnostic output is not necessary and exceeds minimum disclosure requirements.

Attack Path

  1. A valid EODHD token is loaded from configuration or passed to EODHDClient.
  2. A request fails because of an HTTP error, connectivity problem, TLS error, timeout, or deliberately invalid request.
  3. The exception handler returns params, which contains the plaintext api_token.
  4. Agent code, application logging, telemetry, debugging output, or a user-facing response serializes the returned dictionary.
  5. A party with access to that output obtains the token an ...[truncated 492 chars]
Remediation
View remediation

Remediation Suggestions

  • Never return authentication parameters in error objects.
  • Construct a sanitized diagnostic dictionary and replace the token with a fixed value such as [REDACTED].
  • Prefer returning only an error type, a concise message, and an HTTP status code.
  • Ensure application logs and Agent responses apply credential redaction as a defense-in-depth measure.
  • Avoid mutating a caller-supplied parameter dictionary when adding authentication data.

Example:

python
request_params = dict(params or {})
request_params["api_token"] = self.api_token
request_params["fmt"] = "json"

try:
    response = requests.get(url, params=request_params, timeout=30)
    response.raise_for_status()
    return response.json()
except requests.exceptions.RequestException as e:
    return {
        "error": str(e),
        "url": url,
        "params": {
            key: ("[REDACTED]" if key == "api_token" else value)
            for key, value in request_params.items()
        },
    }

T09 · Insecure Skill Coding Practices

Note
Location
SKILL.md:29
Finding

API Token Stored Persistently in a Plaintext Configuration File

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 29-38; supporting implementation in scripts/eodhd_client.py, lines 18-24
Vulnerability Type: Insecure plaintext credential storage
Risk Level: Low

Complete Code Snippet:

markdown
1.  **Ask the user** for their EODHD API token.
2.  **Write the token** to the configuration file using the `file` tool:

    ```python
    default_api.file(
        action="write",
        path="/home/ubuntu/skills/eodhd-api/config.json",
        text=f"{{\"api_token\": \"{user_provided_token}\"}}"
    )
    ```

The corresponding credential-loading implementation is:

python
if api_token:
    self.api_token = api_token
else:
    config_path = os.path.join(os.path.dirname(__file__), '..', 'config.json')
    if not os.path.exists(config_path):
        raise FileNotFoundError("config.json not found. Please create it with your API token.")
    with open(config_path, 'r') as f:
        config = json.load(f)
    self.api_token = config.get("api_token")

The distributed config.json contains only the placeholder YOUR_API_TOKEN; no live hardcoded credential was found.

Technical Analysis

The documented setup procedure directs the Agent to place a personal API credential in a predictable plaintext file inside the Skill directory. It does not require restrictive filesystem permissions, exclude the file from version control, or recommend a secret-management mechanism.

Persisting a credential is not inherently malicious, but unrestricted plaintext storage creates unnecessary exposure to other local users, unrelated processes with filesystem access, backup systems, packaging operations, and accidental source-control commits. The API client already accepts an api_token argument, so persistent package-local storage is not strictly required for its declared functionality.

Attack Path

  1. The user supplies a valid EODHD token. 2 ...[truncated 907 chars]
Remediation
View remediation

Remediation Suggestions

  • Prefer an environment variable or operating-system secret store instead of a package-local configuration file.
  • Allow callers to supply the token at runtime without persisting it.
  • If file storage is unavoidable, create the file with owner-only permissions such as 0600.
  • Store credentials outside the Skill source directory.
  • Add config.json and equivalent secret-bearing files to .gitignore and packaging exclusion rules.
  • Retain a separate example file containing only a placeholder, such as config.example.json.
  • Document token rotation and immediate revocation procedures for suspected disclosure.
  • Ensure logs, exceptions, backups, and generated artifacts do not include the credential.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill describes code-driven behavior that reads local configuration and performs outbound API requests, but it does not declare an explicit tool scope such as allowed tools or permissions. That increases the risk of overbroad agent execution, because a runtime may permit file or network access not clearly constrained by the skill contract, making review and policy enforcement harder.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill instructs the agent to persist a user-provided API token directly into a local config file without any warning, consent flow, or handling guidance for secrets. Storing credentials in plaintext can expose them to other tools, logs, future prompts, or unintended file reads, leading to credential theft and unauthorized API usage.

Content

No source excerpt is available for this finding.