Back to skill

Security audit

Garmin Tracker

Security checks for vulnerabilities and agentic risk

Overview

The skill appears purpose-built for Garmin tracking sync, but it handles Garmin credentials in an unsafe command-line fallback and uses an authenticated browser session, so it should be reviewed before installation.

Install only if you are comfortable giving this skill access to an authenticated Garmin browser session and allowing it to update garmin_tracking.json. Prefer browser/manual login mode, avoid the credentials fallback, and do not pass your Garmin password on the command line. If used, keep it limited to a dedicated browser profile and a workspace containing only the intended tracking file.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/sync_training_plan.mjs:55
Finding

Garmin Credentials Exposed Through Command-Line Arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/sync_training_plan.mjs:55-59
Additional Location: SKILL.md:123-131
Vulnerability Type: Sensitive credential exposure through process arguments
Risk Level: Medium

javascript
} else if (token === "--garmin-email") {
  args.garminEmail = argv[++i] ?? null;
} else if (token === "--garmin-password") {
  args.garminPassword = argv[++i] ?? null;
}

The documented invocation explicitly encourages passing the Garmin password on the command line:

bash
node {baseDir}/scripts/sync_training_plan.mjs \
  --auth-source credentials \
  --garmin-email "user@example.com" \
  --garmin-password "***" \
  --file garmin_tracking.json \
  --write

Technical Analysis

The script reads the Garmin password directly from process.argv. Command-line arguments are not an appropriate secret transport mechanism because they may be exposed through:

  • Process inspection utilities and operating-system process metadata.
  • Shell command history.
  • Terminal session recording and command telemetry.
  • Process supervisors, audit systems, and diagnostic reports.
  • Wrapper scripts or automation logs that record the full invocation.

The password remains referenced by the args object throughout the process lifetime. Although the reviewed code does not intentionally write it to the tracking file or standard output, using command-line arguments unnecessarily broadens its exposure.

Attack Path

  1. The user follows the credentials fallback example in SKILL.md.
  2. The Garmin email and password are included in the shell command.
  3. The command is retained in shell history, captured by telemetry, or exposed through process inspection while the script runs.
  4. A local user, monitoring process, compromised extension, or later reader of the command history retrieves the credentials.
  5. The attacker uses those credentials to attempt access to the vi ...[truncated 522 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove the --garmin-password command-line option and its documentation.
  2. Prefer the existing authenticated browser-session workflow.
  3. If credential authentication must remain available, obtain the password through a non-echoing interactive prompt or a protected file descriptor.
  4. For unattended execution, integrate with an operating-system credential store or approved secret manager rather than environment variables or command arguments.
  5. Keep the credential in the smallest possible scope and overwrite or release references immediately after the login attempt.
  6. Document that credentials must never be placed in shell history, configuration files, logs, or tracking data.
  7. Consider disabling credential-based fallback by default and requiring an explicit operator-controlled policy to enable it.

T08 · Insecure Dependencies

Note
Location
SKILL.md:13
Finding

Unpinned Runtime Installation of Third-Party Browser Automation Dependency

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:13-18
Additional Location: scripts/sync_training_plan.mjs:21-39
Vulnerability Type: Unpinned dependency installation and mutable supply-chain resolution
Risk Level: Low

markdown
## Runtime Prerequisite

- `playwright-core` must be available in the runtime where the skill executes.
- If you get `MODULE_NOT_FOUND: playwright-core`, install it in the active workspace:

```bash
npm install playwright-core
text

The installed package is subsequently loaded and executed by the synchronization script:

```javascript
async function loadChromium() {
  try {
    const mod = await import("playwright-core");
    if (mod?.chromium) {
      return mod.chromium;
    }
  } catch {
    // Fall through to image-level fallback.
  }

  try {
    const mod = await import("/app/node_modules/playwright-core/index.js");
    if (mod?.chromium) {
      return mod.chromium;
    }
  } catch {
    // Fall through to explicit error.
  }

  throw new Error(
    "playwright-core is not available. Install it in the workspace (npm install playwright-core) or ensure the OpenClaw image includes /app/node_modules/playwright-core.",
  );
}

Technical Analysis

The installation command does not specify an audited version, and the project contains no reviewed package manifest or lockfile. Consequently, the dependency version and transitive dependency graph are resolved from mutable registry state at installation time.

This creates a supply-chain risk: the code executed in the environment may differ from what was reviewed. A compromised package release, registry account, dependency, or package-resolution configuration could introduce unauthorized code. Package lifecycle scripts may also execute during installation unless explicitly disabled.

This audit did not find evidence that playwright-core is currently malicious. The finding conce ...[truncated 1057 chars]

Remediation
View remediation

Remediation Suggestions

  1. Add a project package.json that pins playwright-core to a specifically reviewed version.
  2. Commit a generated package-lock.json to make dependency resolution reproducible.
  3. Replace ad hoc installation instructions with npm ci.
  4. Use npm ci --ignore-scripts where compatible, or explicitly review all required lifecycle scripts.
  5. Configure an approved registry and enforce package integrity verification.
  6. Use automated dependency vulnerability and provenance scanning.
  7. Update dependencies through a controlled review process rather than resolving the latest version at runtime.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
87% confidence
Finding

The code's core function is local JSON normalization and summary recomputation. It parses fields like distance, duration, pace, heart rate, and calories from an already-loaded JSON document, keeps history entries on or after 2026-02-01, preserves some fields, and writes the reconciled result if requested. There is no network access, authentication, scraping, API usage, or any Garmin web interaction. Therefore the declared description overstates and misrepresents the actual behavior: the fixed-schema/date aspect is accurate, but the claimed source of data ('from Garmin web data') and implied rebuild/maintenance from Garmin web content are not implemented in this code chunk.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
`sync_training_plan.mjs` supports:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill explicitly instructs reading and writing garmin_tracking.json and invoking local scripts that modify files, but it does not declare any tool scope such as allowed tools or permissions. Missing scope declarations weaken least-privilege controls and can let an agent use file capabilities without clear policy boundaries or user visibility.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill includes a credentials fallback with direct command-line examples containing email and password arguments. Even though the text says not to store or echo credentials, passing secrets via shell arguments is dangerous because they can be exposed in shell history, process listings, logs, or orchestration telemetry.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code explicitly accepts raw Garmin email and password values as runtime arguments, which are highly likely to be exposed via shell history, process listings, job logs, or orchestration metadata. For a skill whose purpose is rebuilding a local tracking JSON from Garmin web data, direct credential collection is broader than necessary and creates avoidable secret-handling risk.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script automates an interactive Garmin sign-in flow using supplied credentials and a browser connected over CDP. Even if intended to recover access when a session is signed out, this expands the skill from passive data synchronization into credential handling and automated authentication, increasing the risk of credential exposure, misuse, or unintended submission into the wrong browser/page context.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.