Back to skill

Security audit

Whoop Connect

Security checks for vulnerabilities and agentic risk

Overview

This WHOOP connector is mostly purpose-aligned, but it handles sensitive health data and tokens while documenting an unauthenticated public webhook setup and weak local secret/storage practices.

Review before installing. This skill is not clearly malicious, but it will access and store sensitive WHOOP health, profile, body, and token data. Avoid enabling the public webhook server unless you add authentication, rate limiting, and replay protection; keep credentials out of systemd unit files and shared shell profiles; and treat ~/.whoop/whoop.db and token.json as sensitive local files.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/webhook_server.py:41
Finding

Public Webhook Accepts Unauthenticated and Forged Events

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/whoop_client.py:155
Finding

OAuth Authorization State Is Generated but Not Validated

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/db.py:14
Finding

Local Health Database Permissions Are Not Explicitly Restricted

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/install.sh:22
Finding

Runtime Dependencies Are Installed Without Version or Integrity Pinning

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
references/setup-guide.md:79
Finding

Deployment Guide Embeds the WHOOP Client Secret in a Systemd Unit

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
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Rogue AgentSelf-Modification, Session Persistence
Findings (27)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared purpose centers on retrieving and storing WHOOP biometric/workout data for use in OpenClaw. This code chunk does not perform that primary function. Instead, it implements a setup wizard and config manager: it loads/saves configuration, prompts for preferences, enables webhook-related options, and outputs config JSON. While these settings may support a WHOOP integration, the actual behavior here is materially different from the declared main capability. Therefore this chunk is a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
72% confidence
Finding

The README instructs users to provision long-lived OAuth client credentials via environment variables, which creates a session persistence and secret-handling risk if the host environment is shared, logged, or inspected by other processes. In the context of a health-data skill, compromise of these credentials could enable continued access to sensitive WHOOP data and token minting beyond a single interactive session.

Content

Scanner excerpt · README.md (reported line 17)May include surrounding context.

md
## Why do I need a developer account?

WHOOP doesn't have a public API. To let your agent read your data, you need to create a free developer app on WHOOP's platform (takes ~5 minutes). This gives you OAuth credentials so the skill can read **your own data only**. All data stays local — nothing is uploaded.

## Setup

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The setup section states the OAuth credentials let the skill read the user's own data only and that all data stays local. Elsewhere, the README explicitly lists a webhook server and real-time webhooks as features, which adds an inbound network service and event-reception behavior beyond a simple local data reader/sync tool.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The wording promises a narrowly scoped, read-only local data access model. The same README later documents a webhook server/event receiver and push notifications, which contradict the impression that the skill only performs local reads of user-owned data via OAuth.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill requests or implies use of powerful capabilities—environment variables, shell execution, network access, and local file writes—without declaring any explicit tool scope or permission boundaries. That makes it harder for the host to enforce least privilege and increases the chance an agent can execute setup/auth/sync commands or write config/state files without clear user-visible constraints.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

md
## Why do I need a developer account?

WHOOP doesn't have a public API — you can't just pull your data with a simple request. To let your AI agent read your recovery, sleep, and workout data, you need to create a free "developer app" on WHOOP's platform. This gives you a pair of credentials (Client ID + Client Secret) that authorize the skill to access **your own data only**, using the industry-standard OAuth protocol.

- It's free and takes about 5 minutes
- You're only granting **read access** to your own account

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

Line L009 gives an absolute assurance that data is stored locally and "nothing is uploaded anywhere." Later lines describe configuring a public HTTPS server and registering a webhook URL with WHOOP so data/events are transmitted to that endpoint, which contradicts the earlier plain-language claim.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest describes a skill for connecting a WHOOP wearable to fetch and store recovery, sleep, HRV, strain, and workout data locally. This guide adds an optional deployment model involving a publicly exposed webhook server, reverse proxy, health endpoint, systemd service, and scheduled sync infrastructure, which goes materially beyond simple local data retrieval/storage.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module docstring presents this daemon as part of WHOOP Connect's syncing/storage behavior, but the implementation in the main loop only calls API methods, compares IDs from the local DB, and prints new recovery/sleep/workout events. There is no code here that inserts or updates the local database with newly fetched records, which is a material mismatch with the stated purpose of fetching and storing data locally.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This module persistently stores highly sensitive health and profile data locally, including recovery metrics, sleep details, HRV, heart rate, email, and body measurements, but the code shows no encryption, access controls, retention limits, or consent/disclosure mechanism. In the context of a wearable-data connector, local persistence is expected, but storing regulated-style health data in plaintext under a predictable path increases privacy and compromise risk if the host account or filesystem is accessed.

Content

No source excerpt is available for this finding.

Context Window Stuffing

Medium
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Content

Scanner excerpt · scripts/db.py (reported line 178)May include surrounding context.

python
sleep_consistency_percentage,
         baseline_milli, need_from_sleep_debt_milli,
         need_from_recent_strain_milli, need_from_recent_nap_milli)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    """, (
        data["id"], data.get("cycle_id"), data["user_id"],
        data["created_at"], data["updated_at"], data["start"], data["end"],

Context Window Stuffing

Medium
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.

Content

Scanner excerpt · scripts/db.py (reported line 208)May include surrounding context.

python
percent_recorded,
         zone_zero_milli, zone_one_milli, zone_two_milli,
         zone_three_milli, zone_four_milli, zone_five_milli)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    """, (
        data["id"], data["user_id"], data["created_at"], data["updated_at"],
        data["start"], data["end"], data["timezone_offset"],

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · scripts/install.sh (reported line 15)May include surrounding context.

sh
exit 1
fi

# Create venv if it doesn't exist
if [ ! -d "$VENV_DIR" ]; then
    echo "Creating virtual environment..."
    python3 -m venv "$VENV_DIR"

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 · scripts/install.sh (reported line 36)May include surrounding context.

sh
# Create data directory
mkdir -p ~/.whoop
chmod 700 ~/.whoop

echo "✓ Dependencies installed (venv at ${VENV_DIR})"
echo ""

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/api-reference.md (reported line 3)May include surrounding context.

md
from db import get_db, upsert_recovery, upsert_sleep, upsert_workout, upsert_cycle, upsert_profile, upsert_body, get_daily_api_calls, increment_api_calls
from formatters import format_recovery, format_sleep, format_workout, format_cycle, format_profile, format_trends

BASE_URL = "https://api.prod.whoop.com/developer"
AUTH_URL = "https://api.prod.whoop.com/oauth/oauth2/auth"
TOKEN_URL = "https://api.prod.whoop.com/oauth/oauth2/token"
REDIRECT_URI = "http://localhost:3000/callback"

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/api-reference.md (reported line 9)May include surrounding context.

md
from db import get_db, upsert_recovery, upsert_sleep, upsert_workout, upsert_cycle, upsert_profile, upsert_body, get_daily_api_calls, increment_api_calls
from formatters import format_recovery, format_sleep, format_workout, format_cycle, format_profile, format_trends

BASE_URL = "https://api.prod.whoop.com/developer"
AUTH_URL = "https://api.prod.whoop.com/oauth/oauth2/auth"
TOKEN_URL = "https://api.prod.whoop.com/oauth/oauth2/token"
REDIRECT_URI = "http://localhost:3000/callback"

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/api-reference.md (reported line 10)May include surrounding context.

md
from db import get_db, upsert_recovery, upsert_sleep, upsert_workout, upsert_cycle, upsert_profile, upsert_body, get_daily_api_calls, increment_api_calls
from formatters import format_recovery, format_sleep, format_workout, format_cycle, format_profile, format_trends

BASE_URL = "https://api.prod.whoop.com/developer"
AUTH_URL = "https://api.prod.whoop.com/oauth/oauth2/auth"
TOKEN_URL = "https://api.prod.whoop.com/oauth/oauth2/token"
REDIRECT_URI = "http://localhost:3000/callback"

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/whoop_client.py (reported line 18)May include surrounding context.

python
from db import get_db, upsert_recovery, upsert_sleep, upsert_workout, upsert_cycle, upsert_profile, upsert_body, get_daily_api_calls, increment_api_calls
from formatters import format_recovery, format_sleep, format_workout, format_cycle, format_profile, format_trends

BASE_URL = "https://api.prod.whoop.com/developer"
AUTH_URL = "https://api.prod.whoop.com/oauth/oauth2/auth"
TOKEN_URL = "https://api.prod.whoop.com/oauth/oauth2/token"
REDIRECT_URI = "http://localhost:3000/callback"

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/whoop_client.py (reported line 19)May include surrounding context.

python
from db import get_db, upsert_recovery, upsert_sleep, upsert_workout, upsert_cycle, upsert_profile, upsert_body, get_daily_api_calls, increment_api_calls
from formatters import format_recovery, format_sleep, format_workout, format_cycle, format_profile, format_trends

BASE_URL = "https://api.prod.whoop.com/developer"
AUTH_URL = "https://api.prod.whoop.com/oauth/oauth2/auth"
TOKEN_URL = "https://api.prod.whoop.com/oauth/oauth2/token"
REDIRECT_URI = "http://localhost:3000/callback"

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/whoop_client.py (reported line 20)May include surrounding context.

python
from db import get_db, upsert_recovery, upsert_sleep, upsert_workout, upsert_cycle, upsert_profile, upsert_body, get_daily_api_calls, increment_api_calls
from formatters import format_recovery, format_sleep, format_workout, format_cycle, format_profile, format_trends

BASE_URL = "https://api.prod.whoop.com/developer"
AUTH_URL = "https://api.prod.whoop.com/oauth/oauth2/auth"
TOKEN_URL = "https://api.prod.whoop.com/oauth/oauth2/token"
REDIRECT_URI = "http://localhost:3000/callback"

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The OAuth scope list includes read:profile and read:body_measurement, which grants access to personal and biometric data not clearly needed for the advertised functionality. Overbroad scopes increase the blast radius of token compromise and create unnecessary exposure of sensitive health-related information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

OAuth access and refresh tokens are persisted to ~/.whoop/token.json without any user-facing disclosure that credentials will be stored for ongoing reuse. Even with file mode 0600, silent persistence of long-lived refresh tokens can surprise users and increases risk if the local account or filesystem is later compromised.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The client silently writes retrieved recovery, sleep, workout, cycle, profile, and body data into a local database without any visible consent, retention notice, or storage controls. Because this is sensitive health and biometric information, undisclosed persistence materially increases privacy harm and the consequences of local compromise or secondary use.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill fetches and stores WHOOP profile and body data even though the stated skill purpose emphasizes recovery, sleep, HRV, strain, and workout data. Collecting additional health/profile attributes beyond the declared scope violates data minimization and increases privacy risk because users may authorize more sensitive data than necessary without clear expectation.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The README lists generic natural-language requests such as "How's my recovery today?" and "How did I sleep last night?" without clarifying whether these are merely examples or the actual invocation triggers. Because these phrases overlap with ordinary conversation, an agent or router could match them more broadly than intended.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.