Back to skill

Security audit

Nordpool Fi

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims: fetches Finnish electricity prices from a public API and calculates charging windows, with some reliability caveats.

Install only if you are comfortable with the skill making outbound requests to api.porssisahko.net when used. Treat the charging-window output as advisory because the timezone handling and API error handling should be improved before relying on it for automated or high-cost scheduling.

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

Warning
Location
bin/nordpool-fi.py:12
Finding

Unbounded Network Wait and Remote Response Size

Content
View full analysis

Vulnerability Details

File Location: bin/nordpool-fi.py, lines 12–13
Vulnerability Type: Unbounded external API request and response processing
Risk Level: Medium

Vulnerable Code

python
with urllib.request.urlopen(req) as response:
    return json.loads(response.read().decode())

Technical Analysis

The external HTTPS request does not specify a timeout. Consequently, an unavailable, slow, or malicious upstream service may leave the process waiting indefinitely.

The code also calls response.read() without imposing a maximum response size. The complete response is loaded into memory before JSON decoding and parsing. If the API endpoint or its delivery path returns an excessively large body, the process may consume substantial memory or terminate due to resource exhaustion.

TLS reduces the likelihood of an arbitrary network attacker modifying the response, but it does not protect against upstream compromise, service malfunction, DNS or trust-store compromise, or unexpectedly large legitimate responses. The code also does not validate the response content type or schema before processing it.

Attack Path

  1. An attacker compromises or gains control over the configured API endpoint or a trusted component in its delivery path.
  2. When the skill requests https://api.porssisahko.net/v2/latest-prices.json, the attacker either delays the response indefinitely or returns an excessively large body.
  3. Because no timeout is configured, a delayed response can block the skill process.
  4. Because no response-size limit is enforced, an oversized response is loaded into memory in full.
  5. The process experiences prolonged blocking, excessive memory consumption, or termination.

Impact Assessment

The issue can cause denial of service within the privileges and resource limits of the skill process. It does not directly grant code execution, elevated privileges, credential access, or persistence. Its scope is limited to process avai ...[truncated 109 chars]

Remediation
View remediation

Remediation Suggestions

  • Configure a finite timeout when opening the URL, appropriate to the expected API latency.
  • Read the response incrementally and enforce a strict maximum byte count before decoding or parsing it.
  • Reject responses whose declared Content-Length exceeds the limit, while still enforcing the limit during streaming because that header may be absent or inaccurate.
  • Validate that the response has the expected JSON content type.
  • Validate the parsed object against an explicit schema, including the expected prices collection and required field types.
  • Handle timeout, size-limit, decoding, and schema-validation failures separately and return a controlled error.
  • Consider applying runtime memory and execution-time limits as an additional containment measure.

A hardened implementation should follow this pattern:

python
MAX_RESPONSE_BYTES = 2 * 1024 * 1024
REQUEST_TIMEOUT_SECONDS = 10

with urllib.request.urlopen(
    req, timeout=REQUEST_TIMEOUT_SECONDS
) as response:
    content_type = response.headers.get_content_type()
    if content_type != "application/json":
        raise ValueError("Unexpected response content type")

    body = response.read(MAX_RESPONSE_BYTES + 1)
    if len(body) > MAX_RESPONSE_BYTES:
        raise ValueError("API response exceeds the permitted size")

    data = json.loads(body.decode("utf-8"))
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (4)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill invokes a network-capable script but the manifest does not declare any tool scope such as permissions or allowed-tools. This weakens least-privilege controls and makes network access implicit rather than reviewable, which can hide unexpected outbound requests or future capability creep.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · bin/nordpool-fi.py (reported line 8)May include surrounding context.

python
from datetime import datetime, timedelta, timezone

def get_data():
    url = "https://api.porssisahko.net/v2/latest-prices.json"
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
    }

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The code comments claim Finland winter/summer handling, but the implementation always applies a fixed UTC+2 offset. During daylight saving time Finland uses UTC+3, so hourly grouping, current-hour matching, and charging-window calculations can be shifted by one hour, producing incorrect recommendations that could cause mistimed charging or misleading price statistics.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The description and keywords explicitly constrain the skill to Finland ("Hourly electricity prices for Finland", keyword "finland") without any natural-language indication that this locale restriction is optional or user-selected. Under the policy rule for language/locale constraints, this can be treated as a locale-specific limitation that is not justified in the file itself.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.