Back to skill

Security audit

iaqualink-curl

Security checks for vulnerabilities and agentic risk

Overview

This skill is not clearly malicious, but it needs Review because a read-oriented pool-status helper includes credential-backed commands that can change real pool equipment state and cache session tokens.

Install only if you intentionally want a shell helper that can sign into iAqualink and may be used to control pool, spa, heater, auxiliary, and chlorinator state. Prefer the safer MCP path for writes, use IAQ_DRY_RUN before testing commands, avoid scripting generic iaq_command calls, and delete the session file when you no longer need cached access.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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 (13)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

md
# Assistant uses (see the repo's docs/IAQUALINK-API.md); only the login
# endpoint + app key have been confirmed live (a fake account got a 401).
#
# Credentials come from the macOS Keychain item with service "iaqualink":
#   security add-generic-password -s iaqualink -a 'you@example.com' -w
# (the account attribute is the email, the password is the secret). For a dry
# run or a test, IAQ_EMAIL / IAQ_PASSWORD override the Keychain.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/iaqualink.sh (reported line 9)May include surrounding context.

sh
# Assistant uses (see the repo's docs/IAQUALINK-API.md); only the login
# endpoint + app key have been confirmed live (a fake account got a 401).
#
# Credentials come from the macOS Keychain item with service "iaqualink":
#   security add-generic-password -s iaqualink -a 'you@example.com' -w
# (the account attribute is the email, the password is the secret). For a dry
# run or a test, IAQ_EMAIL / IAQ_PASSWORD override the Keychain.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/iaqualink.sh (reported line 12)May include surrounding context.

sh
# Assistant uses (see the repo's docs/IAQUALINK-API.md); only the login
# endpoint + app key have been confirmed live (a fake account got a 401).
#
# Credentials come from the macOS Keychain item with service "iaqualink":
#   security add-generic-password -s iaqualink -a 'you@example.com' -w
# (the account attribute is the email, the password is the secret). For a dry
# run or a test, IAQ_EMAIL / IAQ_PASSWORD override the Keychain.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/iaqualink.sh (reported line 55)May include surrounding context.

sh
# Assistant uses (see the repo's docs/IAQUALINK-API.md); only the login
# endpoint + app key have been confirmed live (a fake account got a 401).
#
# Credentials come from the macOS Keychain item with service "iaqualink":
#   security add-generic-password -s iaqualink -a 'you@example.com' -w
# (the account attribute is the email, the password is the secret). For a dry
# run or a test, IAQ_EMAIL / IAQ_PASSWORD override the Keychain.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill documents shell-based capabilities but does not declare an explicit tool scope such as allowed-tools or permissions. That mismatch weakens containment and review because consumers may treat the skill as documentation-only while it can drive command execution and network access through a sourced shell helper.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The text explicitly says to use the skill for reads and debugging, yet later includes write procedures. That contradiction increases the chance of operator error and unsafe automation because the context suggests a lower-risk usage model than the content actually supports.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill presents itself as intended for reads/debugging, but it also documents state-changing commands that can toggle pumps, heaters, auxiliaries, and chlorinator settings. This inconsistency can mislead users or higher-level agents into invoking write operations under a read-only trust assumption, potentially causing unsafe or costly physical-world changes.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · references/iaqualink.sh (reported line 34)May include surrounding context.

sh
security find-generic-password -s iaqualink -w 2>/dev/null
}

# _iaq_curl <args...>: run curl, or print it when IAQ_DRY_RUN=1. Bodies always
# arrive on stdin (--data @-) so the password never appears in `ps`.
_iaq_curl() {
  if [ "${IAQ_DRY_RUN:-}" = "1" ]; then

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · references/iaqualink.sh (reported line 60)May include surrounding context.

sh
fi
  if [ "${IAQ_DRY_RUN:-}" = "1" ]; then
    jq -n --arg k "$IAQ_API_KEY" --arg e "$email" --arg p "$pw" '{api_key:$k,email:$e,password:$p}' |
      _iaq_curl -X POST https://prod.zodiac-io.com/users/v1/login --data @-
    return 0
  fi
  out=$(jq -n --arg k "$IAQ_API_KEY" --arg e "$email" --arg p "$pw" '{api_key:$k,email:$e,password:$p}' |

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · references/iaqualink.sh (reported line 64)May include surrounding context.

sh
fi
  if [ "${IAQ_DRY_RUN:-}" = "1" ]; then
    jq -n --arg k "$IAQ_API_KEY" --arg e "$email" --arg p "$pw" '{api_key:$k,email:$e,password:$p}' |
      _iaq_curl -X POST https://prod.zodiac-io.com/users/v1/login --data @-
    return 0
  fi
  out=$(jq -n --arg k "$IAQ_API_KEY" --arg e "$email" --arg p "$pw" '{api_key:$k,email:$e,password:$p}' |

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The script persists authentication material including authentication_token, session_id, id_token, and refresh_token to disk. Although it uses umask 077, storing long-lived tokens in a predictable file path creates a reusable secret cache that could be abused by local malware, backups, or other processes running as the same user.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% 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 · references/iaqualink.sh (reported line 79)May include surrounding context.

sh
iaq_refresh() {
  local out
  out=$(jq -n --arg e "$(_iaq_get email)" --arg r "$(_iaq_get refresh_token)" '{email:$e,refresh_token:$r}' |
    _iaq_curl -X POST https://prod.zodiac-io.com/users/v1/refresh --data @-) || return 1
  [ "${IAQ_DRY_RUN:-}" = "1" ] && { printf '%s\n' "$out"; return 0; }
  local tmp="$IAQ_SESSION.tmp"
  (umask 077 && jq --argjson n "$out" '. + {authentication_token: $n.authentication_token,

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script advertises read-oriented usage but exposes a generic iaq_command wrapper that can invoke arbitrary backend commands, including state-changing toggles. In a shell helper context, this broad capability increases the chance of accidental or unauthorized operational changes to physical equipment if the function is reused or scripted without strict command allowlisting.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
references/iaqualink.sh:20