Back to skill

Security audit

OpenSprinkler

Security checks for vulnerabilities and agentic risk

Overview

The skill does what it claims, but it controls physical irrigation hardware using a reusable password hash over plaintext HTTP and exposes broad state-changing actions with weak guardrails.

Review before installing. Use this only on a trusted, isolated local network with a strong unique OpenSprinkler password, and be aware that any agent invocation can send authenticated commands that start or stop watering, disable operation, change delays, or reboot the controller. Prefer a version that enforces duration and ID bounds, separates read-only from write/admin tools, and requires explicit confirmation for disruptive actions.

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

Error
Location
handler.py:13
Finding

Reusable Controller Credential Transmitted Over Plaintext HTTP

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
handler.py:127
Finding

Insufficient Validation of Physical Controller Operation Parameters

Content
View full analysis
0."}) res = make_request(f"/cm?sid={sid}&en=1&t={duration}") else: res = make_request(f"/cm?sid={sid}&en=0") return json.dumps(res) def start_program(args): """Starts a pre-configured program. Native API pid is 1-based.""" program_id = args.get("program_id") use_weather = 1 if args.get("use_weather", True) else 0 if not program_id: return json.dumps({"error": "program_id is required."}) res = make_request(f"/mp?pid={program_id}&uwt={use_weather}") return json.dumps(res) def run_once(args): """Converts a highly readable dictionary into the 72-element API array.""" station_durations = args.get("station_durations", {}) max_stations = 72 t_array = [0] * max_stations # Map dictionary (e.g., {"1": 600}) to the 0-based array for stat_id_str, duration in station_durations.items(): try: sid = int(stat_id_str) - 1 if 0 <= sid < max_stations: t_array[sid] = int(duration) except ValueError: pass t_json = urllib.parse.quote(json.dumps(t_array)) res = make_request(f"/cr?t={t_json}") return json.dumps(res) def pause_queue(args): """Temporarily pauses the watering queue (e.g., while walking a dog).""" duration = args.get("duration_seconds", 0) res = make_req ...[truncated 3621 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (9)

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · handler.py (reported line 27)May include surrounding context.

python
try:
        req = urllib.request.Request(url)
        with urllib.request.urlopen(req) as response:
            return json.loads(response.read().decode())
    except Exception as e:
        return {"error": str(e)}

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill declares environment variables for a controller IP address and password and is explicitly designed to interact with a local HTTP API, but it does not define any tool scope restrictions such as allowed tools or permissions. That creates unnecessary ambient authority: an agent using this skill may be able to access network and secret-bearing environment data more broadly than intended, increasing the chance of unintended device control or credential exposure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The file reads a sensitive environment variable for the controller password and uses it to make HTTP requests to a device, but there is no confirmation prompt, user-facing logging, or warning comment/docstring disclosing this sensitive access and transmission behavior. Because this skill also performs remote control actions against infrastructure, users are not clearly warned in the code about the privacy and system-impact implications.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill offers numerous state-changing operations—starting stations/programs, queue pause, rain delay changes, global enable/disable, stop-all, and reboot—without any in-code confirmation, bounds checks, or safety interlocks. In an agentic context, mistaken or manipulated tool invocation could cause unintended watering, service interruption, or operational disruption to the irrigation system.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill exposes a reboot_controller capability even though the stated description focuses on monitoring and irrigation control operations. Undisclosed administrative functionality expands the skill’s effective permissions and can disrupt availability of the irrigation controller if invoked unexpectedly.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

Rebooting the controller is an administrative action that is not necessary for ordinary irrigation monitoring and routine station/program control. In this context, it creates avoidable denial-of-service risk by interrupting watering schedules, sensor handling, or manual operations.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

Multiple state-changing tools can start watering, stop watering, disable operation, pause queues, and alter rain delay, but their descriptions do not define when they should or should not be invoked. In an agent setting, vague invocation boundaries increase the chance of unsafe autonomous actions, prompt-induced misuse, or accidental physical-world disruption such as overwatering, skipped irrigation, or service interruption.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest exposes a remote reboot capability that is not necessary for the core user-facing irrigation tasks described for the skill. Even without code-level exploitability shown here, unnecessary power over hardware control expands the attack surface and could let an agent or prompt-influenced workflow disrupt irrigation availability or mask other actions by resetting the controller.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
72% confidence
Finding

All user-facing descriptions are authored only in English, and the file provides no indication that other languages are supported or that language choice is user-selectable. Under the stated policy, forcing a specific language without opt-in can be a locale-policy issue.

Content

No source excerpt is available for this finding.