Back to skill

Security audit

ClawHealth Garmin

Security checks for vulnerabilities and agentic risk

Overview

The skill appears purpose-built for Garmin health syncing, but it handles sensitive credentials and health data while installing and running external code in ways that deserve review before use.

Install only in a trusted, isolated environment. Use a dedicated Garmin password or secret mechanism if available, keep .env, password files, config, sessions, SQLite databases, and raw JSON out of shared workspaces and backups, and prefer pinning the clawhealth package and invoking the virtualenv executable before relying on this for sensitive health data.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T08 · Insecure Dependencies

Warning
Location
bootstrap_deps.py:14
Finding

Unpinned Third-Party Package Allows Reviewed Behavior to Change

Content
View full analysis
=0.1.1", ] ``` ```python print("[clawhealth-garmin] Installing/upgrading dependencies:", ", ".join(REQS)) _run([str(vpy), "-m", "pip", "install", "--upgrade", *REQS]) ``` ### Technical Analysis The Skill delegates its core Garmin authentication and health-data processing to the external `clawhealth` package. The requirement uses a lower-bound version constraint rather than an exact, audited version, and `--upgrade` explicitly permits pip to install newer releases. No lock file, package hashes, or transitive dependency constraints are present. Consequently, the code executed after installation can differ from the code evaluated when this Skill was reviewed. A compromised package release, compromised maintainer account, malicious transitive dependency, or future release with insecure behavior could therefore enter the environment without a corresponding Skill update. This risk is particularly relevant because the dependency is expected to process: - Garmin usernames and passwords - MFA and authenticated session data - Detailed health and activity records - Local SQLite databases and configuration files - Environment variables inherited from the OpenClaw process ### Attack Path 1. An attacker compromises the `clawhealth` package publishing account, release pipeline, or one of its unconstrained transitive dependencies. 2. The attacker publishes a version satisfying `clawhealth>=0.1.1`. 3. A user runs `bootstrap_deps.py`, directly or through the installation command in `SKILL.md`. 4. `pip install --upgrade` selects and installs the attacker-controlled release. 5. Package installation hooks may execute during installation, and the installed package subsequently executes when the Skill invokes the CLI. 6. During normal Garmin operations, the mal ...[truncated 761 chars]
Remediation
View remediation

T07 · Tool Hijacking and Spoofing

Warning
Location
run_clawhealth.py:92
Finding

PATH-Based CLI Resolution Can Execute a Spoofed Clawhealth Binary

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (20)

Credential Access

High
Category
Privilege Escalation
Confidence
74% confidence
Finding

The README explicitly instructs users to create a .env file and a plaintext password file containing Garmin credentials inside the skill workspace. Although framed as local-only configuration, this creates stored secrets on disk in a predictable location that may be exposed through backups, container access, workspace sharing, or accidental inclusion in logs and archives.

Content

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

bash
docker exec -it openclaw bash -c '
cd ~/.openclaw/workspace/skills/clawhealth-garmin &&
printf "CLAWHEALTH_GARMIN_USERNAME=you@example.com\nCLAWHEALTH_GARMIN_PASSWORD_FILE=./garmin_pass.txt\n" > .env &&
printf "YOUR_PASSWORD" > garmin_pass.txt &&
chmod 600 .env garmin_pass.txt &&
echo "Configuration complete. Return to the chat UI and trigger login."

Credential Access

High
Category
Privilege Escalation
Confidence
77% confidence
Finding

The Docker example writes both .env and garmin_pass.txt with plaintext credential material inside the container filesystem using a shell one-liner. This increases secret exposure risk because the values may be captured in terminal history, orchestration logs, shell audit trails, copied container layers/snapshots, or accessible to other processes/users with workspace access.

Content

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

cd ~/.openclaw/workspace/skills/clawhealth-garmin && printf "CLAWHEALTH_GARMIN_USERNAME=you@example.com\nCLAWHEALTH_GARMIN_PASSWORD_FILE=./garmin_pass.txt\n" > .env && printf "YOUR_PASSWORD" > garmin_pass.txt && chmod 600 .env garmin_pass.txt && echo "Configuration complete. Return to the chat UI and trigger login." '

text

Hidden Instructions

High
Category
Prompt Injection
Confidence
60% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · README_zh.md (reported line 1)May include surrounding context.

md
# clawhealth-garmin

将 Garmin Connect 健康数据同步到本地 SQLite,并以 JSON 接口提供给 OpenClaw / AI Agent 使用。

Credential Access

High
Category
Privilege Escalation
Confidence
82% confidence
Finding

The README instructs users to place account credentials into .env and a local password file inside the skill directory. Although intended for configuration, this still creates a credential-handling risk because secrets are stored on disk in a workspace location that may be backed up, copied, exposed to other local processes, or accidentally committed.

Content

Scanner excerpt · README_zh.md (reported line 125)May include surrounding context.

bash
docker exec -it openclaw bash -c '
cd ~/.openclaw/workspace/skills/clawhealth-garmin &&
printf "CLAWHEALTH_GARMIN_USERNAME=you@example.com\nCLAWHEALTH_GARMIN_PASSWORD_FILE=./garmin_pass.txt\n" > .env &&
printf "YOUR_PASSWORD" > garmin_pass.txt &&
chmod 600 .env garmin_pass.txt &&
echo "配置完成,请回到聊天界面触发登录。"

Credential Access

High
Category
Privilege Escalation
Confidence
82% confidence
Finding

This Docker example writes both .env and the password file directly inside the skill workspace, making credential persistence easy but increasing the chance of accidental disclosure through image snapshots, volume mounts, backups, logs, or later file access from other tools in the environment. The risk is amplified because the example is copy-paste ready and normalizes storing secrets beside code.

Content

Scanner excerpt · README_zh.md (reported line 127)May include surrounding context.

cd ~/.openclaw/workspace/skills/clawhealth-garmin && printf "CLAWHEALTH_GARMIN_USERNAME=you@example.com\nCLAWHEALTH_GARMIN_PASSWORD_FILE=./garmin_pass.txt\n" > .env && printf "YOUR_PASSWORD" > garmin_pass.txt && chmod 600 .env garmin_pass.txt && echo "配置完成,请回到聊天界面触发登录。" '

text

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_clawhealth.py (reported line 10)May include surrounding context.

python
def _load_env(path: Path) -> None:
    """Load key=value pairs from a simple .env file if present.

    This is deliberately minimal and only used to wire credentials and
    configuration for the skill. It does not override existing env vars.

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_clawhealth.py (reported line 30)May include surrounding context.

python
def _load_env(path: Path) -> None:
    """Load key=value pairs from a simple .env file if present.

    This is deliberately minimal and only used to wire credentials and
    configuration for the skill. It does not override existing env vars.

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_clawhealth.py (reported line 83)May include surrounding context.

python
def _load_env(path: Path) -> None:
    """Load key=value pairs from a simple .env file if present.

    This is deliberately minimal and only used to wire credentials and
    configuration for the skill. It does not override existing env vars.

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_clawhealth.py (reported line 84)May include surrounding context.

python
base_dir = Path(__file__).resolve().parent

    # 1) Load .env if present (credentials, DB/config overrides, etc.)
    _load_env(base_dir / ".env")

    # 2) Set default config/db locations under the skill directory
    _set_skill_defaults(base_dir)

Session Persistence

Medium
Category
Rogue Agent
Confidence
71% confidence
Finding

The skill documentation promotes persistent storage of authentication material and states that Garmin login session data will be stored locally in the config directory. Persistent credentials and session tokens increase the blast radius of local compromise because an attacker who gains filesystem access may reuse them to access the user's Garmin account and health data without re-authentication.

Content

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

It is recommended to use a password file instead of storing the password directly in an environment variable.

Create .env in the skill directory:

text
CLAWHEALTH_GARMIN_USERNAME=you@example.com

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README explicitly states that the skill may fetch code from GitHub at runtime and may automatically install missing dependencies. This creates a real supply-chain and arbitrary code execution risk because the executed code is not fully contained in the reviewed skill package, and users may trigger network downloads and package installation implicitly during normal use.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

bash
echo "YOUR_PASSWORD" > garmin_pass.txt
chmod 600 garmin_pass.txt

说明:

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

bash
echo "YOUR_PASSWORD" > garmin_pass.txt
chmod 600 garmin_pass.txt

说明:

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README_zh.md (reported line 96)May include surrounding context.

bash
echo "YOUR_PASSWORD" > garmin_pass.txt
chmod 600 garmin_pass.txt

说明:

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · README_zh.md (reported line 127)May include surrounding context.

bash
echo "YOUR_PASSWORD" > garmin_pass.txt
chmod 600 garmin_pass.txt

说明:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill advertises shell, environment-variable, and file-read capabilities but does not declare an explicit tool scope such as permissions or allowed-tools. That omission weakens reviewability and least-privilege enforcement, making it easier for an agent or operator to invoke the skill without understanding it can execute shell commands, read local files, and access secrets from env vars.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill requires Garmin credentials and network access to Garmin Connect, but the description does not explicitly warn that account credentials and personal account data are transmitted to an external online service. In a health-data context, that omission reduces informed consent and can lead users to expose highly sensitive data without appreciating the network privacy 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 description states that it syncs Garmin health data into SQLite and persists raw JSON payloads, but it does not prominently warn users that sensitive health information will be stored locally. Because the data includes personal wellness and potentially intimate medical-adjacent details, users may enable the skill without informed consent or adequate protection of the resulting local database and raw payload files.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

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

python
def _run(cmd: list[str]) -> None:
    proc = subprocess.run(cmd)
    if proc.returncode != 0:
        raise SystemExit(proc.returncode)

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · run_clawhealth.py (reported line 94)May include surrounding context.

python
# 4) Delegate to the installed `clawhealth` CLI
    try:
        result = subprocess.run(["clawhealth", *sys.argv[1:]])
        return result.returncode
    except FileNotFoundError:
        sys.stderr.write(

Static analysis

No suspicious patterns detected.