Back to skill

Security audit

Ostrom Energy

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly transparent about fetching energy prices, but it also enables broad local command execution and unsafe local config loading.

Review before installing. Use the price and optimize features only with credentials you are comfortable storing locally, avoid the optional installer if you do not want a persistent wrapper in ~/.local/bin, do not use untrusted .env files, and do not enable --execute or pass on/off commands unless you wrote and verified the exact shell command yourself.

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

T09 · Insecure Skill Coding Practices

Error
Location
ostrom_energy.py:293
Finding

Arbitrary Shell Command Execution Through Price-Control Actions

Content
View full analysis
ON command", args.on_command, execute) action_taken = True if args.price_above is not None and price >= args.price_above: if args.off_command: run_cmd("Price is above threshold -> OFF command", args.off_command, execute) action_taken = True ``` ### Technical Analysis The values supplied through `--on-command` and `--off-command` are passed directly to `subprocess.run()` with `shell=True`. The shell consequently interprets metacharacters, command substitutions, pipelines, redirections, and chained commands contained in these arguments. Although execution requires the explicit `--execute` option and the Skill documents that command strings must be trusted, there is no technical restriction limiting ...[truncated 1577 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
ostrom_energy.py:113
Finding

Configurable Network Endpoints Can Redirect Credentials and Tokens

Content
View full analysis
str: url = auth_base_url.rstrip("/") + "/oauth2/token" credentials = f"{client_id}:{client_secret}".encode("utf-8") basic = base64.b64encode(credentials).decode("ascii") body = urllib.parse.urlencode({"grant_type": "client_credentials"}).encode("utf-8") req = urllib.request.Request( url, data=body, headers={ "Authorization": f"Basic {basic}", "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json", }, method="POST", ) payload = request_json(req) token = payload.get("access_token") if not token: raise RuntimeError(f"OAuth token missing in response: {payload}") return token def fetch_spot_prices( token: str, api_base_url: str, start_date: datetime, end_date: datetime, zip_code: str | None, ): params = { "startDate": to_utc_iso(start_date), "endDate": to_utc_iso(end_date), "resolution": "HOUR", } if zip_code: params["zip"] = zip_code url = api_base_url.rstrip("/") + "/spot-prices?" + urllib.parse.urlencode(params) req = urllib.request.Request( url, headers={ "Authorization": f"Bearer {token}", "Accept": "application/json", }, method="GET", ) payload = request_json(req) ``` The destinations are resolved from environment variables or persistent configuration without validation: ```python api_base_url = resolve_credential( env_name="OSTROM_API_BASE_URL", config=config, config_keys=("api_base_url", "OSTROM_API_BASE_URL"), prompt_missing= ...[truncated 3104 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
run.sh:1
Finding

Local Environment File Is Executed as Bash Code

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (14)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 18)May include surrounding context.

Quick Start

bash
cp .env.example .env
# edit .env with your credentials
bash run.sh prices --hours 24

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 136)May include surrounding context.

md
- Include: `SKILL.md`, `run.sh`, `ostrom-energy`, `install-local-command.sh`, `ostrom_energy.py`, `.env.example`, `config.json.example`, `.gitignore`

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · ostrom_energy.py (reported line 99)May include surrounding context.

python
return cfg_value

    if prompt_missing:
        return prompt_value(prompt_label, is_secret=is_secret)

    return default

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill's stated purpose is energy-price retrieval and optimization, yet it includes a generic mechanism to execute arbitrary shell commands for 'smart-home control.' This expands the privilege boundary far beyond what is necessary for the use case, so any caller able to set these parameters can repurpose the skill for unrelated system command execution.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

This is a direct tool-parameter abuse issue: untrusted command data is passed into a shell interpreter, allowing the skill's command parameters to become a command-execution primitive. Because the skill is likely to be invoked by an automation agent, the surrounding context makes this more dangerous: natural-language or workflow inputs could be translated into shell commands and executed on the host.

Content

Scanner excerpt · ostrom_energy.py (reported line 300)May include surrounding context.

python
def run_cmd(label: str, cmd: str, execute: bool):
    print(f"{label}: {cmd}")
    if execute:
        subprocess.run(cmd, shell=True, check=True)


def command_control(args, token, api_base_url, zip_code):

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · README.md (reported line 19)May include surrounding context.

md
set -euo pipefail
ROOT="$(cd "$(dirname "$0")" && pwd)"

# Auto-load local .env for OSTROM_* variables when present.
if [[ -f "${ROOT}/.env" ]]; then
  set -a
  # shellcheck disable=SC1091

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · run.sh (reported line 5)May include surrounding context.

sh
set -euo pipefail
ROOT="$(cd "$(dirname "$0")" && pwd)"

# Auto-load local .env for OSTROM_* variables when present.
if [[ -f "${ROOT}/.env" ]]; then
  set -a
  # shellcheck disable=SC1091

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · ostrom_energy.py (reported line 19)May include surrounding context.

python
ROOT="$(cd "$(dirname "$0")" && pwd)"

# Auto-load local .env for OSTROM_* variables when present.
if [[ -f "${ROOT}/.env" ]]; then
  set -a
  # shellcheck disable=SC1091
  source "${ROOT}/.env"

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · run.sh (reported line 6)May include surrounding context.

sh
ROOT="$(cd "$(dirname "$0")" && pwd)"

# Auto-load local .env for OSTROM_* variables when present.
if [[ -f "${ROOT}/.env" ]]; then
  set -a
  # shellcheck disable=SC1091
  source "${ROOT}/.env"

Credential Access

High
Category
Privilege Escalation
Confidence
89% confidence
Finding

Sourcing a .env file executes it as shell code, not just as data. If an attacker can modify that file, they can run arbitrary commands when the launcher starts, potentially inheriting the user's privileges and accessing any configured secrets or smart-home credentials used by the skill.

Content

Scanner excerpt · run.sh (reported line 9)May include surrounding context.

sh
if [[ -f "${ROOT}/.env" ]]; then
  set -a
  # shellcheck disable=SC1091
  source "${ROOT}/.env"
  set +a
fi

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 32)May include surrounding context.

If ostrom-energy is not found, run from the skill folder with bash run.sh ....

Alternative (recommended for shared installs): create a persisted config file: ~/.config/ostrom-energy/config.json

bash

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill documentation describes capabilities that involve environment-variable access, filesystem reads, network calls, and shell command execution, but it does not declare any explicit tool scope such as permissions or allowed-tools. This creates an overbroad, implicit trust boundary where an agent may run with more power than users or reviewers expect, increasing the chance of unsafe execution or abuse.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
84% confidence
Finding

The skill instructs users to store persistent credentials in ~/.config/ostrom-energy/config.json, creating session persistence for sensitive OAuth client secrets outside ephemeral execution. Persistent local secret storage increases exposure to later compromise by other local processes, accidental backup/sync leakage, or reuse in unintended sessions.

Content

Scanner excerpt · SKILL.md (reported line 28)May include surrounding context.

OSTROM_ZIP is optional, but recommended to include local taxes/levies and grid/base fees.

For persistent configuration, create ~/.config/ostrom-energy/config.json:

bash
mkdir -p ~/.config/ostrom-energy

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
99% confidence
Finding

The skill executes a user-supplied string with subprocess.run(..., shell=True), which enables arbitrary shell execution if the command argument is influenced by an agent, user, or upstream workflow. In this skill, the 'control' feature is framed as smart-home automation, but the implementation grants full shell access rather than invoking a constrained device API, making command injection and misuse straightforward.

Content

Scanner excerpt · ostrom_energy.py (reported line 300)May include surrounding context.

python
def run_cmd(label: str, cmd: str, execute: bool):
    print(f"{label}: {cmd}")
    if execute:
        subprocess.run(cmd, shell=True, check=True)


def command_control(args, token, api_base_url, zip_code):

Static analysis

No suspicious patterns detected.