Back to skill

Security audit

WHOOP (Official API)

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it says for WHOOP reporting, but it handles sensitive health data and tokens with weak safeguards and ships an under-disclosed partner API surface with privileged write operations.

Review this skill before installing. It can store WHOOP OAuth tokens locally, fetch and persist sensitive health/profile/body data, send summaries to chat channels, and create scheduled pushes. Use a private token/output directory, narrow WHOOP_SCOPES before login, avoid shared /tmp output paths, and do not use or expose the bundled partner API operations unless you explicitly need and control those credentials.

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)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/whoop_oauth_login.py:52
Finding

OAuth Authorization Flow Lacks State and Callback Validation

Content
View full analysis
") code = parse_code(user_in) tok = exchange_code_for_token( code=code, client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri, ) ``` The associated parser at `scripts/whoop_oauth_login.py:34-44` only extracts the authorization code: ```python def parse_code(user_input: str) -> str: s = user_input.strip() if s.startswith("http://") or s.startswith("https://"): u = urllib.parse.urlparse(s) q = urllib.parse.parse_qs(u.query) code = (q.get("code") or [None])[0] if code: return code raise SystemExit("Could not find ?code= in the pasted redirect URL") return s ``` ### Technical Analysis The authorization request does not include a cryptographically random OAuth `state` parameter. The callback parser accepts a redirect URL from any HTTP or HTTPS origin, extracts only its `code`, and does not verify that its scheme, host, port, and path match the configured `WHOOP_REDIRECT_URI`. The authorization code is therefore not bound to the login transaction initiated by this process. Accepting a bare code further prevents callback-origin and state validation. This creates login CSRF or account-binding confusion risk: a valid authorization code generated through a different browser transaction can be submitted and stored by the Skill. PKCE is also absent. Although the client secret is required for exchang ...[truncated 1237 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/whoop_token.py:46
Finding

Sensitive Token and Health Data Files Are Created Through Predictable, Symlink-Following Paths

Content
View full analysis
str: p = path or token_path() _mkdirp(p) tmp = p + ".tmp" with open(tmp, "w", encoding="utf-8") as f: json.dump(token, f, indent=2, sort_keys=True) f.write("\n") os.replace(tmp, p) try: os.chmod(p, 0o600) except PermissionError: pass return p ``` Raw health data is written using ordinary file creation: ```python out_path = args.out with open(out_path, "w", encoding="utf-8") as f: json.dump(bundle, f, indent=2, sort_keys=True) f.write("\n") ``` Normalized data is also written without an explicit restrictive mode: ```python json.dump(out, open(args.out, "w", encoding="utf-8"), indent=2, sort_keys=True) open(args.out, "a", encoding="utf-8").write("\n") ``` The documented workflow uses predictable shared temporary paths: ```bash python3 scripts/whoop_fetch.py --date today --out /tmp/whoop_raw_today.json python3 scripts/whoop_normalize.py /tmp/whoop_raw_today.json --out /tmp/whoop_today.json ``` ### Technical Analysis The token writer creates `token.json.tmp` using `open(..., "w")`. This follows an existing symbolic link and initially uses permissions derived from the process umask. The final token file is changed to mode `0600` only after all token material has been written and moved. The temporary file can consequently expose access and refresh tokens before replacement when its containing directory is accessible and the umask is permissive. The raw and normalized outputs similarly inherit ...[truncated 2017 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/whoop_oauth_login.py:24
Finding

Default OAuth Scopes and Unconditional Fetching Exceed Least-Privilege Requirements

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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (34)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a connector/fetcher skill responsible for authenticating with WHOOP, managing tokens, retrieving WHOOP v2 data, and enabling downstream reporting or chat delivery. The supplied code does none of that. It only processes an already-fetched raw JSON bundle from a file, picks best-matching records by date range, computes a compact summary, and writes output to another file. While the normalized fields relate to WHOOP data domains mentioned in the description, this chunk’s actual purpose is materially narrower and different: offline normalization, not OAuth connection or data retrieval. Therefore the description does not accurately represent this code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description presents a full WHOOP connector/integration with authentication, token lifecycle management, remote API access, and chat update use cases. The actual code chunk is much narrower: it parses an input JSON file and renders a summary string with channel-specific formatting conventions. While the rendered fields relate to WHOOP metrics, the code does not implement the core declared capabilities. This is a material description-to-behavior mismatch rather than a minor implementation detail.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

md
4) The script stores tokens at `WHOOP_TOKEN_PATH`.

If you need to revoke later, use `delete /v2/user/access` (see `references/whoop_api.md`).

## Workflow 2 — Fetch metrics (today / yesterday)

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The OpenAPI spec exposes trusted-partner endpoints for lab requisitions, service requests, token issuance, status updates, and diagnostic report uploads even though the skill description only justifies end-user WHOOP OAuth and fitness metric retrieval/reporting. This creates a capability mismatch that could let the agent request or operate on partner-only medical workflow data if corresponding credentials are ever available, expanding the attack surface far beyond the declared purpose.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

This endpoint explicitly exchanges partner client credentials for an access token, introducing handling of highly sensitive non-user secrets and privileged bearer tokens. In a consumer-facing skill meant for WHOOP OAuth data access, unnecessary support for privileged credential flows raises the risk of secret leakage, token theft, and unauthorized partner API use.

Content

Scanner excerpt · references/openapi.json (reported line 292)May include surrounding context.

json
"post" : {
        "tags" : [ "Partner" ],
        "summary" : "Request a partner client token",
        "description" : "Exchanges partner client credentials for an access token.",
        "operationId" : "requestToken",
        "requestBody" : {
          "content" : {

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The service-request status update endpoint allows modification of external workflow state, which is not justified by the stated use case of connecting to WHOOP and summarizing metrics in chat. Such unnecessary write access increases the chance that prompt injection, agent misuse, or misconfiguration could alter partner records or operational processes.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The diagnostic report upload endpoint is a state-changing medical-data capability unrelated to reading WHOOP recovery, sleep, cycle, workout, profile, or body measurements. In an agent context, retaining this operation means the skill could be induced to create or alter external clinical records, causing integrity and compliance risks well beyond passive fitness reporting.

Content

No source excerpt is available for this finding.

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 · references/openapi.json (reported line 706)May include surrounding context.

json
"/v2/user/access" : {
      "delete" : {
        "tags" : [ "User" ],
        "description" : "Revoke the access token granted by the user. If the associated OAuth client is configured to receive webhooks, it will no longer receive them for this user.",
        "operationId" : "revokeUserOAuthAccess",
        "responses" : {
          "204" : {

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/whoop_api.md (reported line 46)May include surrounding context.

md
- Workout collection: `GET /v2/activity/workout`
- Basic profile: `GET /v2/user/profile/basic`
- Body measurements: `GET /v2/user/measurement/body`
- Revoke access: `DELETE /v2/user/access`

## Pagination

Credential Access

High
Category
Privilege Escalation
Confidence
84% confidence
Finding

The file explicitly stores OAuth access and refresh tokens in a local JSON file, creating a credential exposure risk if the host is multi-user, backups are accessible, or the token path is redirected to an insecure location. Although file mode 0600 is applied after saving, the design still relies on plaintext token-at-rest storage and trusts an environment-controlled path.

Content

Scanner excerpt · scripts/whoop_token.py (reported line 5)May include surrounding context.

python
"""WHOOP token utilities.

- Store tokens in a local JSON file.
- Refresh access tokens when expired.

No third-party deps.
"""

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill documentation instructs use of shell, environment variables, local file storage, and networked OAuth/API access, but it declares no explicit tool scope or allowed-tools boundary. In an agent environment, missing scope restrictions can let the skill be invoked with broader capabilities than necessary, increasing the blast radius if the skill is misused or prompt-injected.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The description includes broad activation phrases like generating reports and sending updates to any chat channel, which could cause the skill to trigger on common health-summary or messaging requests beyond clearly WHOOP-specific intent. Over-broad invocation increases the chance an agent routes unrelated user tasks into a skill that accesses stored OAuth tokens and external data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill handles OAuth client secrets and stores access/refresh tokens locally, but it gives no explicit warning about the sensitivity of those credentials, file permissions, or the risk of exposing redirect URLs and token files. In a multi-user or poorly secured environment, this can lead to credential theft and unauthorized access to personal health data.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The partner token endpoint accepts client credentials and returns an access token, yet the skill description contains no warning that especially sensitive secrets may be handled if this capability is enabled. In an agent ecosystem, undocumented secret-handling paths increase the risk of accidental exposure, unsafe storage, or misuse of privileged partner credentials.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The spec includes state-changing partner operations that can update service-request status and upload results, but the skill description does not warn that using the skill may modify external records. This omission is risky because users may expect read-only WHOOP reporting while the agent actually possesses write-capable actions against third-party systems.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

These schemas document access to privacy-sensitive health and identity data such as recovery scores, HRV, resting heart rate, sleep stages, body measurements, and profile email/name, but the skill description does not prominently warn users about the sensitivity of the data being accessed and stored. In a chat-oriented skill that can also send updates to external channels, inadequate disclosure increases the risk of uninformed consent and oversharing of health information.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
78% confidence
Finding

While a token URL alone is not usually a vulnerability, this specific one exposes a trusted-partner client-credentials flow that is out of scope for the declared fitness-reporting skill. In context, it signals availability of privileged non-user credentials and partner-only access paths that materially increase risk if included unnecessarily.

Content

Scanner excerpt · references/openapi.json (reported line 1750)May include surrounding context.

json
"type" : "oauth2",
        "flows" : {
          "clientCredentials" : {
            "tokenUrl" : "https://api.prod.whoop.com/developer/v2/partner/token",
            "scopes" : {
              "whoop-partner/token" : "Read service requests and upload results."
            }

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The code silently defaults the timezone to Asia/Shanghai when neither --tz nor requested_tz is provided, which can cause health data to be normalized against the wrong day boundary. In this skill, that can misattribute sleep, recovery, cycle, and workout records to the wrong date, leading to inaccurate reports or summaries and possible privacy surprises if data is sent to other chat channels under an incorrect day context.

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 a normalized JSON file containing personal profile fields such as name and email, plus health-derived WHOOP metrics, directly to disk without any consent check, minimization, redaction, or storage protection. In the context of a fitness/health integration, this creates a privacy and data-handling risk because sensitive personal and wellness data may persist on disk, be copied into logs/backups, or be read by other local users or processes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code saves an OAuth token JSON file to a local path, which is a safety-relevant credential-handling operation. Although the module docstring notes that it writes a token file, the interactive flow does not warn the user before saving sensitive credentials or explain the storage implications at the point of action.

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/openapi.json (reported line 7)May include surrounding context.

json
from typing import Any, Dict, Optional


OAUTH_AUTH_URL = "https://api.prod.whoop.com/oauth/oauth2/auth"
OAUTH_TOKEN_URL = "https://api.prod.whoop.com/oauth/oauth2/token"

DEFAULT_TOKEN_PATH = os.path.expanduser("~/.config/openclaw/whoop/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/openapi.json (reported line 932)May include surrounding context.

json
from typing import Any, Dict, Optional


OAUTH_AUTH_URL = "https://api.prod.whoop.com/oauth/oauth2/auth"
OAUTH_TOKEN_URL = "https://api.prod.whoop.com/oauth/oauth2/token"

DEFAULT_TOKEN_PATH = os.path.expanduser("~/.config/openclaw/whoop/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/openapi.json (reported line 1420)May include surrounding context.

json
from typing import Any, Dict, Optional


OAUTH_AUTH_URL = "https://api.prod.whoop.com/oauth/oauth2/auth"
OAUTH_TOKEN_URL = "https://api.prod.whoop.com/oauth/oauth2/token"

DEFAULT_TOKEN_PATH = os.path.expanduser("~/.config/openclaw/whoop/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/openapi.json (reported line 1533)May include surrounding context.

json
from typing import Any, Dict, Optional


OAUTH_AUTH_URL = "https://api.prod.whoop.com/oauth/oauth2/auth"
OAUTH_TOKEN_URL = "https://api.prod.whoop.com/oauth/oauth2/token"

DEFAULT_TOKEN_PATH = os.path.expanduser("~/.config/openclaw/whoop/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/openapi.json (reported line 1733)May include surrounding context.

json
from typing import Any, Dict, Optional


OAUTH_AUTH_URL = "https://api.prod.whoop.com/oauth/oauth2/auth"
OAUTH_TOKEN_URL = "https://api.prod.whoop.com/oauth/oauth2/token"

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

Static analysis

No suspicious patterns detected.