Back to skill

Security audit

Garmin Sync Cn To Global

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to perform the Garmin sync it claims, but it needs Review because it stores Garmin account passwords in plaintext and uses weak local file handling.

Install only if you are comfortable giving this code Garmin CN and Global credentials and storing those passwords locally in plaintext. Use a dedicated Garmin password if possible, run it in a private user account or virtual environment, restrict ~/.config/garmin-sync permissions, avoid shell history exposure for passwords, and rotate/remove credentials if you stop using it.

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

T09 · Insecure Skill Coding Practices

Error
Location
sync.py:52
Finding

Garmin Account Passwords Are Accepted Through Command-Line Arguments and Stored in Plaintext

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
sync.py:96
Finding

Predictable Temporary Archive Path Allows Symbolic-Link File Overwrite

Content
View full analysis
.zip` as a symbolic link to a file writable by the victim. 3. The victim runs the synchronization command. 4. `open(zip_path, 'wb')` follows the symbolic link and truncates or overwrites the target with Garmin archive data. 5. The subsequent ZIP operation may fail, but the target file has already been corrupted. 6. Cleanup may also fail under sticky-directory rules, but that does not reverse the overwrite. ...[truncated 304 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
sync.py:29
Finding

Synchronization State and Failed Activity Metadata Are Written Without Restrictive Permissions

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:7
Finding

Unpinned Third-Party Authentication Dependency Creates Supply-Chain Exposure

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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (8)

Credential Access

High
Category
Privilege Escalation
Confidence
98% confidence
Finding

The skill instructs users to provide account credentials and states they will be stored in ~/.config/garmin-sync/credentials.json, which implies persistent local credential storage. Combined with the later explicit note that storage is in plaintext, this creates a significant risk of credential theft from local compromise, backups, logs, or other processes with file access.

Content

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

md
# Install dependencies
pip install garth

# Set credentials (once, stored in ~/.config/garmin-sync/credentials.json)
garmin-sync set-credentials --email your_email --password your_password

# Sync new activities from CN to Global

Credential Access

High
Category
Privilege Escalation
Confidence
99% confidence
Finding

The documentation explicitly acknowledges that credentials are stored in plaintext. Plaintext secret storage materially increases the chance that Garmin account credentials are exposed through local malware, shared systems, filesystem backups, accidental disclosure, or weak host permissions.

Content

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

md
## Security Considerations

- Credentials are stored in plaintext at `~/.config/garmin-sync/credentials.json`
- Set restrictive file permissions after first run: `chmod 600 ~/.config/garmin-sync/credentials.json`
- Consider using a dedicated/sandbox account for testing
- Review the code before running with your primary credentials

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

Although chmod 600 reduces access for other local users, this line reinforces a design that depends on a plaintext credential file. Hardening permissions helps but does not mitigate exposure to the account owner context, malware, backups, or any process already running as that user, so the underlying credential-handling weakness remains.

Content

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

md
## Security Considerations

- Credentials are stored in plaintext at `~/.config/garmin-sync/credentials.json`
- Set restrictive file permissions after first run: `chmod 600 ~/.config/garmin-sync/credentials.json`
- Consider using a dedicated/sandbox account for testing
- Review the code before running with your primary credentials

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 · sync.py (reported line 24)May include surrounding context.

python
from garth.sso import login

CONFIG_DIR = os.path.expanduser('~/.config/garmin-sync')
CONFIG_FILE = os.path.join(CONFIG_DIR, 'credentials.json')
STATE_FILE = os.path.join(CONFIG_DIR, 'sync_state.json')
FAILED_FILE = os.path.join(CONFIG_DIR, 'failed_records.json')

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 · SKILL.md (reported line 42)May include surrounding context.

md
## Security Considerations

- Credentials are stored in plaintext at `~/.config/garmin-sync/credentials.json`
- Set restrictive file permissions after first run: `chmod 600 ~/.config/garmin-sync/credentials.json`
- Consider using a dedicated/sandbox account for testing
- Review the code before running with your primary credentials

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script stores Garmin account passwords in plaintext JSON on disk, which exposes long-lived credentials to any local process, backup system, or user that can read the file. Although the file is chmodded to 0600, that control is not sufficient against local compromise, credential theft from backups, or accidental disclosure, and the CLI provides no warning before persisting secrets.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The line explicitly states that all output is in English for consistency, which imposes a language choice on users. Under the policy rule, language constraints should either be optional for the user or clearly justified as region-specific or compliance-driven.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The comment and behavior indicate a fixed language policy: output is always in English. This is a natural-language locale choice imposed by the skill with no user option to select another language or opt in.

Content

No source excerpt is available for this finding.