T05 · Unauthorized Access and Privilege Escalation
- 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
Security audit
Security checks for vulnerabilities and agentic risk
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.
scripts/fitbit_oauth_login.py:27Default OAuth scopes exceed the privileges required for daily activity and sleep summaries
scripts/fitbit_oauth_login.py:111OAuth authorization flow lacks state binding and is vulnerable to login CSRF and account confusion
scripts/fitbit_fetch_daily.py:85Raw Fitbit health records are written without restrictive file permissions
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
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")
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
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")
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
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")
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
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")
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.
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.
No suspicious patterns detected.