Back to skill

Security audit

Fitbit (Official API)

Security checks for vulnerabilities and agentic risk

Overview

This Fitbit skill does what it claims at a high level, but it asks for extra Fitbit permissions and writes sensitive health data to local files with weak handling.

Review before installing. Use the narrowest scopes possible, preferably activity and sleep only, set a private output directory instead of /tmp, treat raw and normalized JSON files as sensitive health records, and revoke or rotate Fitbit tokens if you previously authorized the broader default scopes.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/fitbit_oauth_login.py:27
Finding

Default OAuth scopes exceed the privileges required for daily activity and sleep summaries

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fitbit_oauth_login.py:111
Finding

OAuth authorization flow lacks state binding and is vulnerable to login CSRF and account confusion

Content
View full analysis
")) ``` The callback handler accepts the first `code` received at the expected path without verifying that the response corresponds to the authorization request initiated by this process: ```python q = urllib.parse.parse_qs(parsed.query) code = (q.get("code") or [None])[0] if code: got["code"] = code ``` Similarly, copy-and-paste mode extracts a code from any supplied redirect URL without validating a request-specific value. OAuth `state` is intended to bind the authorization response to the initiating client session. Without it, an attacker may substitute an authorization response associated with a different Fitbit account. This is commonly described as login CSRF or account-linking confusion. ### Attack Path One possible copy-and-paste attack path is: 1. An attacker starts an authorization request using the same public client identifier and configured redirect URI. 2. The attacker authorizes access to an attacker-controlled Fitbit account and obtains the resulting redirect URL containing an authorization code. 3. The attacker persuades the victim to paste that URL or code into the skill's login prompt. 4. Because the script does not verify ...[truncated 1158 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fitbit_fetch_daily.py:85
Finding

Raw Fitbit health records are written without restrictive file permissions

Content
View full analysis
Remediation
View remediation
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 (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents a broader Fitbit integration layer with OAuth connect/authorize behavior, local token lifecycle management, normalized Wellness-hub output, and chat digest rendering. The supplied code chunk only performs date resolution, token acquisition through an external helper, two Fitbit GET requests, and raw JSON output to a file. Its primary behavior overlaps partially with the declared fetch-daily-summaries function, but several important declared capabilities are absent from this code chunk, especially OAuth authorization, explicit token storage/refresh handling, normalization into a stable schema, and digest rendering. Therefore the description does not accurately represent what this specific code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The supplied code is a standalone normalization utility, not a full Fitbit integration. Its behavior is limited to parsing an input JSON file, selecting steps, distance, sleep minutes, and sleep score, and emitting a normalized output file. While this partially aligns with the 'normalize into a stable daily JSON shape' portion of the description, the majority of the declared purpose describes capabilities absent from the code: no Fitbit authentication, no token handling, no network/API access, and no chat-oriented digest generation. Therefore the description materially overstates and misrepresents what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code matches only the authorization and local token-saving portion of the description. It creates an OAuth authorization URL, collects an authorization code either by paste or loopback redirect, exchanges that code for a token, and saves the token. However, the declared purpose describes a broader integration that also refreshes tokens, retrieves Fitbit activity and sleep data, normalizes it for a Wellness hub, and renders a digest. None of those data-fetching or presentation behaviors appear in this code chunk. There are no obvious undeclared harmful capabilities; the mismatch is that the implemented behavior is substantially narrower than the declared end-to-end integration.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description covers a full Fitbit integration pipeline, including authentication, token lifecycle management, data retrieval, normalization, and rendering. The supplied code chunk implements only the final rendering step: it parses a local JSON file and formats sleep, steps, and distance into channel-specific output. Because most of the declared primary capabilities are absent from this code chunk, the description does not accurately represent what this specific code actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code is consistent with part of the declared description: it supports Fitbit OAuth token exchange, local token storage, and token refresh. However, the declared purpose describes a broader integration that also fetches Fitbit wellness data, transforms it into a normalized daily JSON structure, and renders a short digest for chat channels. None of those behaviors appear in this code chunk. There are no obvious undeclared malicious or unrelated capabilities, but the actual behavior is materially narrower than the declared end-to-end integration, so this should be flagged as a description/behavior mismatch for this supplied code chunk.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill advertises commands that require network, shell, environment-variable access, and local file reads/writes, but it does not declare an explicit permission or allowed-tools boundary. That weakens least-privilege controls and can cause users or orchestrators to grant broader capabilities than intended, especially because the skill handles OAuth secrets and token files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill handles OAuth credentials, refresh tokens, and personal Fitbit data, and the documentation shows outputs being written to local files, but it does not prominently warn users about local persistence. That can lead to accidental exposure of sensitive health data or long-lived tokens on shared machines, backups, or insecure directories.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Using Asia/Shanghai as a silent default timezone can cause health and activity summaries to be normalized against the wrong day boundary for many users. In a wellness context, that can corrupt data interpretation, create privacy surprises about inferred locale, and reduce trust in daily summaries even if it is not a code-execution risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script performs HTTP requests to Fitbit APIs using a bearer token and fetches user activity and sleep information, but it does not print, log, or document that health data will be retrieved from a remote service. This is a network operation involving sensitive personal data and lacks any visible warning within the code file.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script stores full raw Fitbit API responses, including sensitive health and sleep details, rather than emitting only the minimal normalized daily schema described in the skill metadata. Because --out is an arbitrary path, this increases the chance of unintended local disclosure, persistence of excess sensitive data, and downstream misuse by other components reading the file.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script writes sensitive Fitbit activity and sleep data to any caller-specified path without guardrails, confirmation, or notice. In a skill context that handles health data, unrestricted file output can lead to accidental overwrite of other files, storage in insecure locations, or silent retention of private data beyond what the user expects.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/fitbit_api.md (reported line 5)May include surrounding context.

md
AUTH_URL = "https://www.fitbit.com/oauth2/authorize"
TOKEN_URL = "https://api.fitbit.com/oauth2/token"

DEFAULT_TOKEN_PATH = os.path.expanduser("~/.config/openclaw/fitbit/token.json")

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/fitbit_api.md (reported line 16)May include surrounding context.

md
AUTH_URL = "https://www.fitbit.com/oauth2/authorize"
TOKEN_URL = "https://api.fitbit.com/oauth2/token"

DEFAULT_TOKEN_PATH = os.path.expanduser("~/.config/openclaw/fitbit/token.json")

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/fitbit_api.md (reported line 18)May include surrounding context.

md
AUTH_URL = "https://www.fitbit.com/oauth2/authorize"
TOKEN_URL = "https://api.fitbit.com/oauth2/token"

DEFAULT_TOKEN_PATH = os.path.expanduser("~/.config/openclaw/fitbit/token.json")

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/fitbit_token.py (reported line 20)May include surrounding context.

python
AUTH_URL = "https://www.fitbit.com/oauth2/authorize"
TOKEN_URL = "https://api.fitbit.com/oauth2/token"

DEFAULT_TOKEN_PATH = os.path.expanduser("~/.config/openclaw/fitbit/token.json")

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
74% confidence
Finding

The manifest says the skill should connect/authorize Fitbit and store/refresh tokens locally, which suggests token-based local integration as the primary credential mechanism. This script additionally requires FITBIT_CLIENT_ID and FITBIT_CLIENT_SECRET from environment variables at runtime, introducing secret-environment access not mentioned in the stated purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The argument parser defaults --tz to Asia/Shanghai when FITBIT_TZ is not set, imposing a specific locale assumption on all users. This can violate language/locale policy because the script does not ask for user choice or justify the region-specific default.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.