Back to skill

Security audit

Garmin Connect Sync (国际→国内)

Security checks for vulnerabilities and agentic risk

Overview

This Garmin sync skill appears purpose-aligned, but it has a real command-injection flaw and handles sensitive account and activity data with weak scoping.

Review before installing. This is not judged malicious, but it should be fixed to use execFileSync or spawnSync with validated numeric arguments, pin the garminconnect dependency, narrow triggers, add an explicit sync confirmation, and document where tokens and FIT files are stored and how to delete them.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
index.js:34
Finding

Shell Command Injection Through Unvalidated Handler Parameters

Content
View full analysis
Remediation
View remediation
maximum) { throw new TypeError(`Expected an integer from ${minimum} to ${maximum}`); } return number; } const days = boundedInteger(params.days ?? params.days_back, 7, 1, 365); const maxActivities = boundedInteger( params.max ?? params.max_activities, 10, 1, 100 ); ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/garmin_sync.py:204
Finding

ZIP Path Traversal When Extracting Downloaded FIT Files

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:15
Finding

Unpinned Third-Party Dependency Creates Supply-Chain Exposure

Content
View full analysis
Remediation
View remediation
"] ``` For stronger integrity assurance: 1. Maintain dependencies in a lock file generated from reviewed versions. 2. Use hash-checked installation, such as a requirements file containing `--hash=sha256:...`. 3. Pin all transitive dependencies where the deployment system supports it. 4. Retrieve packages only from an approved package index over authenticated TLS. 5. Scan dependency releases for known vulnerabilities before updating. 6. Review changelogs and security-sensitive authentication changes before changing the pinned version. 7. Rebuild and test the skill in an isolated environment after dependency updates. 8. Run the resulting application with least privilege and restrict unnecessary outbound network access. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (11)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill declares environment-variable and local file storage requirements but does not explicitly scope or document its tool permissions. That creates an authorization and transparency gap: a host may grant broader capabilities than users expect, while the skill handles highly sensitive credentials, OAuth tokens, and downloaded FIT activity files.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The triggers are broad enough to match common conversations about Garmin devices, syncing, sports data, or watches, causing accidental invocation of a credentialed sync workflow. In this context, unintended activation is more dangerous because the skill is designed to access two accounts and persist local artifacts during synchronization.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The description and warnings do not clearly disclose that OAuth tokens are persisted locally and FIT files are cached on disk. This weakens informed consent and can lead users to expose sensitive health/activity data and long-lived authentication material without understanding the local data-retention risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill reads Garmin usernames and passwords from environment variables and injects them into the Python subprocess environment. While the code comments describe configuration, there is no explicit user-facing warning in this file about handling credentials or transmitting them to another process.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

User-facing messages and the skill description are presented in Chinese, and the file does not offer any language selection or opt-in. Under the policy, forcing a specific language without user choice is a natural-language policy violation unless the locale restriction is explicit and justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The sync routine downloads user activity FIT files from one Garmin account and uploads them to another, which is a privacy-relevant network transfer of personal fitness data. Although the module docstring states what the tool does, the executable sync path contains no confirmation prompt or explicit user-facing warning before performing the transfer.

Content

No source excerpt is available for this finding.

Overly Broad Trigger

Low
Category
Trigger Abuse
Confidence
82% confidence
Finding

The trigger '佳明' is very short and likely to match benign discussion unrelated to account synchronization. Because this skill performs authenticated cross-account data transfer, accidental invocation could expose account metadata or prompt unintended sync operations.

Content

No source excerpt is available for this finding.

Overly Broad Trigger

Low
Category
Trigger Abuse
Confidence
84% confidence
Finding

The trigger '同步' is generic and commonly used in many unrelated contexts, making false activation likely. In a skill that handles credentials, downloads data, and uploads to another account, unintended routing to this skill increases privacy and operational risk.

Content

No source excerpt is available for this finding.

Overly Broad Trigger

Low
Category
Trigger Abuse
Confidence
78% confidence
Finding

The trigger '手表' is too generic and can match ordinary conversation about watches or wearables. Although the direct impact is limited, the skill context raises risk because activation may lead into workflows involving stored credentials and health/activity data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The code defines a state file path in the user's home directory (~/.garmin-sync/sync-state.json), indicating persistent local file writes. This file does not clearly warn users that local sync state will be stored on disk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The subprocess is launched with execSync using a shell command string built from args.join(' '), which creates a command-injection risk if any argument contains shell metacharacters. Here, user-influenced values such as days and maxActivities are interpolated into arguments, so a crafted object input could execute arbitrary shell commands with the skill’s privileges.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.exposed_secret_literal

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
index.js:35

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/garmin_sync.py:79