Back to skill

Security audit

Garminskill

Security checks for vulnerabilities and agentic risk

Overview

The skill appears purpose-built for Garmin health syncing, but it asks users to weaken account security and relies on broad sensitive-data access with under-scoped safeguards.

Review carefully before installing. This skill will access your Garmin account, cache long-lived tokens locally, store sensitive health data as readable Markdown, and may run automatically on a schedule. Do not disable Garmin 2FA unless you accept the account-takeover risk, and prefer installing uv through a trusted package manager with reviewed, pinned dependencies.

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

T03 · Remote Payload Retrieval and Execution

Error
Location
README.md:57
Finding

Unverified Remote Installer Is Piped Directly into a Shell

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Error
Location
scripts/sync_garmin.py:1
Finding

Sensitive Runtime Dependencies Are Not Pinned to Reviewed Versions

Content
View full analysis
=3.10" # dependencies = ["garminconnect>=0.2.38", "cloudscraper"] # /// ``` The README additionally recommends retrieving the latest available dependency versions: ```markdown 1. **Update dependencies:** `uv cache clean` then re-run the sync (uv will fetch the latest versions automatically) 2. **Wait and retry.** Cloudflare blocks are often transient. 3. **Check the [garminconnect issues page](https://github.com/cyberjunky/python-garminconnect/issues)** — others may be experiencing the same problem. ``` ### Technical Analysis `garminconnect` is constrained only by a minimum version, while `cloudscraper` has no version constraint. Consequently, `uv run` may install a future release that was not present during the Skill audit. The repository contains no reviewed lockfile or hash-pinned dependency manifest to ensure reproducible resolution. This is particularly sensitive because these dependencies operate directly in the authentication path: - `garminconnect` receives the user's Garmin email and password during setup. - The libraries handle long-lived OAuth tokens stored under `~/.garminconnect/`. - They process sensitive health data returned by Garmin. - They execute locally with the user's filesystem and network privileges. No evidence shows that the currently named packages are malicious. The vulnerability is that future or compromised releases can become part of the Skill automatically without another review. ### Attack Path 1. An attacker compromises a dependency publisher account, package build process, source repository, or package distribution infrastructure. 2. The attacker publishes a malicious version satisfying `garminconnect>=0.2.38 ...[truncated 1152 chars]
Remediation
View remediation
", # "cloudscraper==", # ] ``` 2. Commit a `uv` lockfile or equivalent reproducible dependency manifest. 3. Where supported, verify downloaded distributions using package hashes. 4. Review transitive dependencies as well as the two direct dependencies. 5. Replace the recommendation to clear the cache and automatically fetch latest releases with a controlled upgrade process: - Update versions deliberately. - Review release notes and source changes. - Regenerate the lockfile. - Test authentication and data handling. - Publish the audited dependency set. 6. Use automated vulnerability and package-integrity scanning in CI. 7. Consider isolating the synchronization process using restricted filesystem access and outbound-network controls so dependency compromise has a smaller impact. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/sync_garmin.py:470
Finding

Untrusted Garmin Activity Names Are Written into Agent-Readable Markdown Without Sanitization

Content
View full analysis
0: header_parts.append(f"{distance / 1000:.1f} km") calories = act.get("calories") ``` The generated content is then written to a file without escaping or trust-boundary marking: ```python output_dir.mkdir(parents=True, exist_ok=True) output_file = output_dir / f"{day_str}.md" output_file.write_text("\n\n".join(sections) + "\n") print(f" {day_str}: Written to {output_file}") ``` The Skill instructs the Agent to read these generated files: ```markdown ## Reading Health Data Health files are stored at `{baseDir}/health/YYYY-MM-DD.md` — one file per day. To answer health or fitness questions, read the relevant date's file from the `{baseDir}/health/` directory. If the file doesn't exist for the requested date, run the sync command for that date first. ``` ### Technical Analysis `activityName` crosses an external-data trust boundary: it is obtained through Garmin and inserted verbatim into Markdown later consumed by an AI Agent. The implementation does not escape Markdown metacharacters, remove HTML, normalize control characters, impose a length limit, or label the value as untrusted data. An activity name containing headings, links, HTML, or instruction-like text can therefore change the structure and semantics of the generated docume ...[truncated 1886 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The README explicitly instructs users to disable two-factor authentication on their Garmin account in order to use the skill. This weakens account security for the entire Garmin account, not just this integration, and materially increases the risk of account takeover if credentials are stolen or reused.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The README tells users to disable 2FA without an explicit security warning about the consequences. Omitting that warning makes the guidance more dangerous because users may treat it as routine setup instead of understanding they are reducing a key account-protection control.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill syncs highly sensitive health data into local markdown files and makes that data available to OpenClaw, but the README does not clearly warn users about local exposure, retention, or who/what can read those files. Health metrics such as sleep, heart rate, stress, SpO2, HRV, weight, and activity history are sensitive personal data that could be exposed through filesystem access, backups, indexing, or downstream agent use.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation states that the skill uses cloudscraper to bypass Cloudflare protection on Garmin's SSO. Tooling designed to evade anti-bot protections increases legal, operational, and security risk, and may break unpredictably or encourage users to normalize bypassing platform defenses.

Content

No source excerpt is available for this finding.

Ssd 2

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The documentation describes working around Garmin and Cloudflare anti-bot measures and frames failures as something to retry or update around. This normalizes service-defense evasion and can expose users to account lockouts, ToS violations, and brittle authentication behavior that may fail in unsafe or unexpected ways.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill clearly instructs the agent to run a Python sync script that performs network access to Garmin Connect and writes markdown files to disk, yet it declares no explicit tool scope such as allowed-tools or permissions. This creates an authorization gap: an agent/runtime may permit broader-than-intended file and network actions, making the skill harder to safely sandbox and review.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
The password is prompted interactively via `getpass` — it is never echoed to screen, stored in shell history, or passed as a command argument. On success the user will see `Success! Tokens cached in ~/.garminconnect`. After that, all syncs use cached tokens only — no credentials are needed.

Do not ask the user for their password in chat and do not pass passwords as command-line arguments or via stdin piping, as these methods can expose credentials in process listings or conversation history.

## Syncing Data

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script writes highly sensitive health data such as sleep, heart rate, stress, HRV, SpO2, weight, and activities into local markdown files without an explicit warning, consent step, or guidance on securing the output. On multi-user systems, synced folders, backups, or repos, this can unintentionally expose private medical and lifestyle information to other people or services.

Content

No source excerpt is available for this finding.

External Script Fetching

Low
Category
Supply Chain
Confidence
82% confidence
Finding

The README includes a shell pipeline that downloads and immediately executes a remote install script. While common in developer tooling, this pattern creates supply-chain risk because a compromised server, DNS path, or script update could execute arbitrary code on the user's system.

Content

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

md
- Python 3.10+
- [uv](https://docs.astral.sh/uv/) (no pip install needed — dependencies are inline)
  - macOS: `brew install uv`
  - Linux/WSL: `curl -LsSf https://astral.sh/uv/install.sh | sh`
  - Windows: `powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"`
- A Garmin Connect account (two-factor authentication must be disabled — see [Troubleshooting](#troubleshooting))

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest says the skill provides sleep, activity, heart rate, stress, body battery, HRV, SpO2, and weight data. However, the code also fetches and exports training readiness, respiration, fitness age, and intensity minutes, which expands the skill's functional scope beyond the stated description.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.