Back to skill

Security audit

Whoop Openclaw Skill

Security checks for vulnerabilities and agentic risk

Overview

This Whoop skill is mostly a coherent health-data integration, but it handles OAuth credentials in ways users should review carefully before installing.

Install only if you are comfortable granting read access to sensitive Whoop health data and managing OAuth secrets yourself. Prefer using a local redirect flow or trusted secret store, restrict token/config file permissions, do not send codes or tokens through chat apps, and revoke the Whoop app authorization if a token was exposed.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/whoop_oauth.py:127
Finding

OAuth Tokens Stored Without Restrictive File Permissions

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/whoop_oauth.py:64
Finding

OAuth State Is Generated but Never Validated

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
references/oauth-pages/redirect.html:69
Finding

OAuth Callback Exposes Credentials Through URL, Clipboard, and Messaging Instructions

Content
View full analysis
Access Token:
Copy Token
Next Steps:
  1. Copy the code/token above
  2. Send it to your assistant via Telegram/WhatsApp
  3. Your assistant will configure the integration
  4. You can close this page
``` It obtains tokens directly from the URL query string: ```javascript const urlParams = new URLSearchParams(window.location.search); const code = urlParams.get('code'); const token = urlParams.get('access_token'); const error = urlParams.get('error'); const errorDescription = urlParams.get('error_description'); if (error) { document.getElementById('errorMessage').style.display = 'block'; document.getElementById('errorMessage').textContent = `Error: ${error}${errorDescription ? ' - ' + errorDescription : ''}`; document.querySelector('.success').textContent = '✗'; document.querySelector('.success').style.color = '#dc3545'; document.querySelector('h1').textContent = 'Authorization Failed'; } else if (code) { document.getElementById('authCode').style.display = 'block'; document.getElementById('codeDisplay').textContent = code; } else if (token) { document.getElementById('authToken').style.display = 'block'; document.getElementById('tokenDisplay').textConten ...[truncated 3366 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
README.md:18
Finding

Mutable Installation Artifact and Unpinned Dependency

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
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (37)

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

The README emphasizes indefinite access via automatic refresh of access tokens using refresh tokens, but does not warn that possession of the refresh token effectively grants persistent account access until revoked. In the context of a health-data integration, stolen tokens could allow long-term unauthorized retrieval of sensitive wellness and workout information, making the omission more dangerous than in a low-sensitivity integration.

Content

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

Token Auto-Refresh

No more hourly re-authorization! The skill automatically refreshes your access token using the refresh token. Your token stays valid indefinitely.

If you ever need to manually refresh:

bash

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared purpose focuses on fetching and analyzing health metrics, but the documented behavior also includes OAuth app setup, authorization, token exchange, and local token persistence. This mismatch can mislead users and orchestrators about the sensitivity of the skill, causing it to be invoked in contexts where credential collection and authentication state management were not expected.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The redirect page explicitly displays OAuth authorization material, including access tokens, and tells the user to forward that secret to an assistant over Telegram/WhatsApp. OAuth codes and especially bearer tokens are credentials; exposing them in the browser UI and normalizing manual transfer over consumer messaging channels greatly increases the chance of credential theft, account takeover of the integration, and unauthorized API access. In this skill context, the page is handling health-related Whoop data, so compromise could expose sensitive personal wellness information in addition to API access.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

Displaying an 'Access Token' field in the OAuth redirect page indicates that bearer credentials may be surfaced directly to the end user in the browser. Bearer tokens grant API access to protected resources without additional proof of possession, so exposing them in page content increases the risk of theft via shoulder surfing, screenshots, browser history/context, malicious extensions, or accidental sharing. In a health-data integration, misuse of such a token can lead to sensitive data disclosure.

Content

Scanner excerpt · references/oauth-pages/redirect.html (reported line 70)May include surrounding context.

html
</div>
        
        <div id="authToken" style="display:none;">
            <div class="label">Access Token:</div>
            <div class="code-box" id="tokenDisplay"></div>
            <button class="copy-btn" onclick="copyToken()">Copy Token</button>
        </div>

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The page instructs users to copy OAuth credentials and send them through Telegram/WhatsApp without any warning that these are sensitive secrets. This creates a direct social-engineering and exfiltration path for OAuth material, and any party with access to the message or clipboard can reuse the code/token to impersonate the user to the Whoop API. Because the skill processes personal health and training data, the resulting privacy impact is elevated.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Manually relaying OAuth codes or tokens to an assistant over consumer messaging channels bypasses standard trust boundaries and secure token handling. This pattern turns a controlled OAuth exchange into a human-mediated secret-sharing workflow, making interception, misdelivery, chat history retention, device compromise, and insider misuse realistic attack paths. Given the skill's access to Whoop account data, exploitation could expose private health metrics and enable unauthorized use of the integration.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

The instructions explicitly guide the user to obtain an access token and store it for reuse, but do not describe safeguards for protecting that credential. Exposure of a reusable API token could allow an attacker to access sensitive health and activity data, and the skill context makes this more serious because the data includes recovery, sleep, HRV, and other personal biometric information.

Content

Scanner excerpt · references/whoop-api.md (reported line 10)May include surrounding context.

md
1. Go to https://app.whoop.com/
2. Navigate to Settings → Developer
3. Create a new application
4. Complete OAuth flow to get access token
5. Store token in `~/.whoop_token` or set `WHOOP_API_TOKEN` environment variable

Token refresh is required when token expires (check API response for 401 errors).

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 · SKILL.md (reported line 66)May include surrounding context.

md
raise ValueError(f"No Whoop API token found. Set WHOOP_API_TOKEN or create {self.token_file}")
    
    def _refresh_token(self):
        """Refresh expired access token using refresh token"""
        refresh_token_file = Path(self.token_file).parent / ".whoop_refresh_token"
        
        if not refresh_token_file.exists():

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

python
raise ValueError(f"No Whoop API token found. Set WHOOP_API_TOKEN or create {self.token_file}")
    
    def _refresh_token(self):
        """Refresh expired access token using refresh token"""
        refresh_token_file = Path(self.token_file).parent / ".whoop_refresh_token"
        
        if not refresh_token_file.exists():

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 · scripts/whoop_oauth.py (reported line 96)May include surrounding context.

python
raise ValueError(f"No Whoop API token found. Set WHOOP_API_TOKEN or create {self.token_file}")
    
    def _refresh_token(self):
        """Refresh expired access token using refresh token"""
        refresh_token_file = Path(self.token_file).parent / ".whoop_refresh_token"
        
        if not refresh_token_file.exists():

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 · scripts/whoop_oauth.py (reported line 105)May include surrounding context.

python
raise ValueError(f"No Whoop API token found. Set WHOOP_API_TOKEN or create {self.token_file}")
    
    def _refresh_token(self):
        """Refresh expired access token using refresh token"""
        refresh_token_file = Path(self.token_file).parent / ".whoop_refresh_token"
        
        if not refresh_token_file.exists():

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 · scripts/whoop_oauth.py (reported line 160)May include surrounding context.

python
raise ValueError(f"No Whoop API token found. Set WHOOP_API_TOKEN or create {self.token_file}")
    
    def _refresh_token(self):
        """Refresh expired access token using refresh token"""
        refresh_token_file = Path(self.token_file).parent / ".whoop_refresh_token"
        
        if not refresh_token_file.exists():

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 · scripts/whoop_oauth.py (reported line 174)May include surrounding context.

python
raise ValueError(f"No Whoop API token found. Set WHOOP_API_TOKEN or create {self.token_file}")
    
    def _refresh_token(self):
        """Refresh expired access token using refresh token"""
        refresh_token_file = Path(self.token_file).parent / ".whoop_refresh_token"
        
        if not refresh_token_file.exists():

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

python
self.token = new_access_token
            self.headers["Authorization"] = f"Bearer {new_access_token}"
            
            print("✅ Access token auto-refreshed!", file=sys.stderr)
            return True
        else:
            raise ValueError(f"Token refresh failed: {response.status_code} - {response.text}")

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The script prints part of the received access token to stdout, which can leak sensitive credentials into terminal scrollback, shell logging, CI logs, remote session transcripts, or support screenshots. Even partial token disclosure is unnecessary and unsafe for secrets tied to private health data access.

Content

Scanner excerpt · scripts/whoop_oauth.py (reported line 117)May include surrounding context.

python
expires_in = token_data.get("expires_in")
            
            print("\n" + "=" * 70)
            print("✅ SUCCESS! Access token received")
            print("=" * 70)
            print(f"\n🔑 Access Token:\n{access_token[:20]}...{access_token[-20:]}")

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

The script prints part of the refresh token, a long-lived credential that can be used to mint new access tokens and maintain persistent account access. Exposure through console logs or transcripts is especially dangerous because refresh tokens often outlive access tokens and enable ongoing access to sensitive health information.

Content

Scanner excerpt · scripts/whoop_oauth.py (reported line 119)May include surrounding context.

python
print("\n" + "=" * 70)
            print("✅ SUCCESS! Access token received")
            print("=" * 70)
            print(f"\n🔑 Access Token:\n{access_token[:20]}...{access_token[-20:]}")
            
            if refresh_token:
                print(f"\n🔄 Refresh Token:\n{refresh_token[:20]}...{refresh_token[-20:]}")

Credential Access

High
Category
Privilege Escalation
Confidence
94% confidence
Finding

This line writes the access token to a plaintext file in the home directory without explicit permission hardening or secure secret storage. That creates a credential exposure risk to other local processes, users, backups, and malware, especially given the health-data scope of the Whoop account.

Content

Scanner excerpt · scripts/whoop_oauth.py (reported line 129)May include surrounding context.

python
# Save both access and refresh tokens
            DEFAULT_TOKEN_FILE.write_text(access_token)
            print(f"\n💾 Access token saved to: {DEFAULT_TOKEN_FILE}")
            
            if refresh_token:
                refresh_file = DEFAULT_TOKEN_FILE.parent / ".whoop_refresh_token"

Credential Access

High
Category
Privilege Escalation
Confidence
96% confidence
Finding

This line writes the refresh token to a plaintext file, enabling persistent reuse of the account if the file is later read or copied. Because refresh tokens support silent re-authentication, compromise here has greater persistence and impact than access-token leakage alone.

Content

Scanner excerpt · scripts/whoop_oauth.py (reported line 135)May include surrounding context.

python
refresh_file = DEFAULT_TOKEN_FILE.parent / ".whoop_refresh_token"
                refresh_file.write_text(refresh_token)
                print(f"💾 Refresh token saved to: {refresh_file}")
                print("\n✨ Refresh token will auto-renew your access token when it expires!")
            print("\n" + "=" * 70)
            print("🎉 SETUP COMPLETE!")
            print("=" * 70)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The README instructs users to place OAuth client_id and client_secret into a local JSON file and later use long-lived refresh capability, but it provides no warning about securing that file, excluding it from version control, or protecting refresh/access tokens. In a skill that handles health-account API access, this omission can lead to credential leakage through shell history, backups, shared machines, or accidental repository commits, enabling unauthorized access to sensitive user data.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill describes capabilities that involve network access, reading configuration files, and writing tokens to disk, but it does not declare any explicit tool scope or permission boundaries. That increases the chance the host agent grants broader access than users expect, making credential handling and external API access less transparent and harder to constrain.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The activation text is broad enough to match generic health, training, briefing, trend, or alert requests, not just clearly Whoop-specific ones. In a multi-skill system this can cause over-triggering, leading the agent to request or use sensitive fitness data when the user did not intend to invoke this integration.

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 · SKILL.md (reported line 18)May include surrounding context.

md
- Python 3.7+
- `requests` library: `pip install requests`

**Step 1: Create Whoop Developer App**

1. Go to https://app.whoop.com/ → Settings → Developer
2. Click "Create Application"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation instructs users to place a client secret in a local JSON file and states that tokens are saved to ~/.whoop_token, but it does not warn that these are sensitive secrets or recommend file permission hardening. If stored insecurely, local users, backups, logs, or other processes could read reusable OAuth credentials and access private health data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The README documents a redirect page that extracts an OAuth authorization code from the URL and automatically copies it to the clipboard. Authorization codes are sensitive short-lived credentials; automatically placing them in the clipboard increases the chance of accidental disclosure to other applications, browser extensions, shared clipboard services, or user mishandling, especially since the README provides no warning about the sensitivity of the code.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script automatically copies the authorization code or token into the system clipboard after page load, without a clear consent step. Clipboard contents are broadly accessible to the user and potentially to other applications or browser contexts, so silently placing secrets there increases the risk of unintended disclosure and accidental pasting into chats, logs, or other unsafe destinations. In combination with the page's instruction to message the secret, this makes exfiltration even easier.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.