Back to skill

Security audit

Garmin Health Analysis

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly aligned with Garmin health analysis, but it handles credentials, health data, and GPS route files with several under-scoped security and privacy controls.

Review before installing. Use an isolated virtual environment with pinned dependencies, avoid entering passwords on the command line or storing them in plaintext config files, protect or delete ~/.clawdbot/garmin token material when revoking access, choose a private output directory for activity files, and avoid generated dashboards unless you accept the third-party Chart.js CDN exposure.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (6)

T08 · Insecure Dependencies

Error
Location
install.sh:18
Finding

Unpinned dependencies are installed into user or system Python environments

Content
View full analysis
/dev/null; then echo "✓ Dependencies installed (--user)" elif pip3 install --break-system-packages garminconnect fitparse gpxpy 2>/dev/null; then echo "✓ Dependencies installed (--break-system-packages)" elif pip3 install garminconnect fitparse gpxpy 2>/dev/null; then echo "✓ Dependencies installed (system-wide)" else echo "❌ Failed to install Python dependencies" echo " Try manually: pip3 install --user garminconnect fitparse gpxpy" exit 1 fi ``` Related unpinned installation instructions also appear in: - `SKILL.md:7` - `SKILL.md:25-31` - `README.md:23-28` - `references/mcp_setup.md:21-32` ### Technical Analysis The installer retrieves the latest available releases of three executable Python packages without version constraints, hashes, or a lock file. The effective code installed can therefore change after the Skill itself has been reviewed. The `--break-system-packages` fallback bypasses Python's externally managed environment protection. The final fallback may modify a system-wide Python environment, depending on the invoking user's privileges and local `pip` configuration. These installation scopes are broader than necessary for the Skill, which can operate from an isolated virtual environment. Suppressing standard error with `2>/dev/null` also hides package verification, dependency-conflict, and environment-integrity warnings that could be security-relevant. ### Attack Path 1. An attacker compromises one of the named PyPI packages, one of its transitive dependencies, or the publisher account. 2. The attacker publishes a malicious version. 3. A user runs `install. ...[truncated 732 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/garmin_auth.py:127
Finding

Garmin passwords can be exposed through command-line arguments

Content
View full analysis
config.json > environment variables if not email or not password: config = load_config() if config: email = email or config.get("email") password = password or config.get("password") if not email or not password: email = email or os.getenv("GARMIN_EMAIL") password = password or os.getenv("GARMIN_PASSWORD") if not email or not password: print("❌ Email and password required", file=sys.stderr) print("Set via:", file=sys.stderr) print(" 1. CLI: --email and --password", file=sys.stderr) print(" 2. Config: create config.json from config.example.json", file=sys.stderr) print(" 3. Env vars: GARMIN_EMAIL and GARMIN_PASSWORD", file=sys.stderr) print(" 4. Clawdbot config: skills.entries.garmin-health-analysis.env", file=sys.stderr) sys.exit(1) success = login(email, password) ``` The unsafe invocation is explicitly recommended in `SKILL.md:82-87`: ```bash python3 scripts/garmin_auth.py login \ --email YOUR_EMAIL@example.com \ --password YOUR_PASSWORD ``` ### Technical Analysis Command-line arguments are not an appropriate channel for account passwords. Depending on the operating system and process config ...[truncated 1174 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
install.sh:34
Finding

Plaintext credential configuration is created without restrictive permissions

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/garmin_activity_files.py:27
Finding

Predictable shared temporary files allow symlink overwrite and local data disclosure

Content
View full analysis
Remediation
View remediation

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/garmin_chart.py:20
Finding

Mutable third-party JavaScript executes in dashboards containing private health data

Content
View full analysis
{title} ``` Private Garmin values are embedded into the same page at `scripts/garmin_chart.py:119-125`: ```html
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/garmin_auth.py:21
Finding

Incorrect token-store documentation prevents reliable session revocation

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (25)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The code is only a focused activity-file utility, not a general natural-language Garmin analytics skill. It does match a subset of the description: downloading FIT/GPX files, extracting route/activity data, querying by point in an activity, and basic activity analysis. However, the declared purpose strongly emphasizes broad conversational access to many wellness and readiness metrics plus dashboard generation, none of which are implemented here. The primary behavior is materially narrower than described, so this is a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The description promises a broad end-user capability for querying and analyzing Garmin health/activity data. This code chunk does not implement those features; it is solely an authentication helper. While authentication could be a supporting component of the larger skill, the evaluation is against the supplied code chunk, whose actual behavior is materially narrower and different from the declared purpose. It also handles sensitive credentials and stores tokens locally, which is not mentioned in the description. Therefore the description does not accurately represent what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The code is clearly Garmin-data related, so it aligns at a high level with the declared domain. However, the description substantially overstates the implemented functionality in this code chunk. The script only provides command-line access to a small set of metrics and outputs JSON. It does not implement natural-language interaction, FIT/GPX export/download, route or point-by-point elevation/pace analysis, interactive dashboards, or many of the named metrics such as VO2 max, training readiness, body composition, and SPO2. Additionally, it fetches user profile information including name/display name/email, which is not declared. This is a material description-versus-behavior mismatch rather than a minor implementation detail.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The description presents a broad conversational Garmin analytics skill with route-file downloads, route-point analysis, and dashboard generation. The supplied code chunk only implements direct retrieval of specific Garmin metrics via command-line arguments and JSON output. While some declared areas overlap (training readiness, body composition, SPO2, VO2/max-related data, intraday heart rate), several headline capabilities in the description are absent from this code, especially natural-language interaction, FIT/GPX download, route analysis, and dashboard creation. This is a material description-behavior mismatch for the provided chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents a comprehensive Garmin conversational analytics skill with many data domains and advanced analysis/download/dashboard features. The supplied code chunk only implements time-based lookup for four specific metrics via command-line arguments. This is a materially narrower actual behavior than the declared purpose. There is no evidence in this chunk of natural-language understanding beyond simple time parsing, no support for the many additional declared metrics, and none of the file download, route analysis, or dashboard capabilities. This is therefore a description-behavior mismatch due to substantial overstatement of implemented capabilities.

Content

No source excerpt is available for this finding.

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 · references/mcp_setup.md (reported line 28)May include surrounding context.

md
# Install and setup
npm install
pip3 install garminconnect fitparse gpxpy
cp .env.example .env
# Edit .env with your credentials

# Authenticate

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 · references/mcp_setup.md (reported line 29)May include surrounding context.

md
npm install
pip3 install garminconnect fitparse gpxpy
cp .env.example .env
# Edit .env with your credentials

# Authenticate
npm run auth

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill requests and documents use of sensitive capabilities including environment variables, local file read/write, and shell execution, but does not declare any explicit tool scope restrictions. In an agent setting, missing least-privilege boundaries increases the chance the skill can access more data or execute more commands than users expect, especially since it handles credentials and token files.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The description advertises very general prompts such as "how did I sleep last night?" and "show me this week's workouts" without defining any trigger boundary or exclusion conditions. In a manifest/markdown context, these are common conversational phrases that could overlap with everyday chat and make it unclear when this skill should activate versus a general assistant response.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
88% confidence
Finding

The skill instructs users to persist credentials in a local config.json and also stores reusable session tokens in a fixed path. Persistent secret storage expands the window for compromise from local malware, backups, accidental file sharing, or weak file permissions, especially given the sensitivity of Garmin health and activity data.

Content

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

Option B: Local Config File

Create a config file in the skill directory:

bash
cd ~/.clawdbot/skills/garmin-health-analysis

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documentation recommends passing credentials via command-line arguments without warning that process arguments can be exposed through shell history, process listings, logs, crash reports, or multi-user system telemetry. Because the skill handles account credentials for sensitive health data, this omission materially increases the chance of secret leakage.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The privacy statement says no data is sent anywhere except Garmin, yet generated HTML is opened automatically in the default browser. If the chart page loads remote assets such as Chart.js from a CDN, or if the browser sync/telemetry stack processes the page, sensitive health data may be exposed to third parties contrary to user expectations.

Content

No source excerpt is available for this finding.

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 · install.sh (reported line 34)May include surrounding context.

sh
exit 1
fi

# Create config from example if it doesn't exist
if [ ! -f "config.json" ] && [ -f "config.example.json" ]; then
    echo
    echo "📝 Creating config.json from example..."

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documentation explicitly shows extracting and reusing OAuth tokens for session persistence, but it does not warn that these tokens are sensitive bearer credentials equivalent to an authenticated session. In a health-data skill, leaked session tokens could let an attacker access highly sensitive Garmin account data, including activity, sleep, heart rate, and other personal health information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The document advertises broad access to medical-adjacent personal data including heart rate, stress, Body Battery, SPO2, respiration, body composition, and recovery metrics, but gives no warning that these are sensitive personal health signals. In a health-analysis skill, omission of sensitivity and handling guidance can lead to overcollection, inadvertent disclosure, or unsafe user expectations about how such data should be treated.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The activity-file features explicitly support downloading, parsing, and mapping FIT/GPX data, which can reveal precise GPS routes alongside physiological metrics such as heart rate and pace. Presenting these capabilities without any privacy warning or consent guidance increases the risk that users expose highly sensitive location and health data, especially when routes can reveal home, workplace, or daily routines.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The guide begins with broad phrasing about using it whenever a user asks about their health, trends, or insights, which can cause the skill logic to activate on vague health-related requests that were not intended for this specialized Garmin workflow. In a health context, unintended activation is more concerning because it can lead to unsolicited interpretation of sensitive biometric data or overconfident health guidance based on generic prompts.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The example trigger 'how am I doing?' is overly generic and could match many unrelated wellness, emotional, or medical queries, causing the skill to run without clear user intent to analyze Garmin data. Because this skill handles health-adjacent information, ambiguous triggering increases the risk of misleading responses, privacy surprises, or analysis outside the proper data context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file includes setup steps to place credentials into a .env file and later notes that authentication tokens are shared and stored in local filesystem paths. Because SQP-2 applies to markdown files, the documentation should explicitly warn users about the sensitivity of these credentials and tokens, and the privacy/security implications of storing or sharing them locally.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This script accepts Garmin credentials via command-line arguments, a local config.json file, and environment variables without warning users about the exposure tradeoffs. CLI arguments can be visible to other local users via process listings and shell history, and storing passwords in config files or long-lived environment variables increases the chance of credential disclosure on a machine that also contains sensitive health data access tokens.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The profile endpoint returns directly identifying information, including full name and email address, even though the skill is primarily described as a health-metrics and activity analysis tool. Emitting this PII to stdout makes it broadly available to downstream agent components, logs, and transcripts, increasing unnecessary privacy exposure beyond the minimum data needed for the stated functionality.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This script fetches highly sensitive health data and profile data, then serializes it directly to stdout as JSON without any privacy controls, consent gating, or output minimization. In agent environments, stdout is commonly captured by orchestrators, logs, traces, and other tools, so sensitive biometric and identity data can be exposed far beyond the immediate user interaction.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This script fetches highly sensitive health data, including heart rate, body composition, SPO2, hydration, stress, and training metrics, then prints the results directly to stdout as JSON without any privacy notice, confirmation step, masking, or output-scope restriction. In agent/tooling environments, stdout is often captured in logs, chat transcripts, or intermediary systems, which can expose personal health information beyond the user's intended audience.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The script performs authenticated access to a user's Garmin account and retrieves sensitive health telemetry without any built-in user-facing notice, confirmation, or disclosure at the point of execution. In an agent-skill context, this is risky because health data is highly sensitive, and a user may not realize that a natural-language query triggers external account access and data retrieval.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

This code saves downloaded Garmin activity data to a local file in the specified output directory, defaulting to /tmp. Although the function has a docstring, there is no explicit user-facing disclosure at the point of execution that a file containing potentially sensitive GPS and health data will be written to disk.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.