Back to skill

Security audit

WHOOP Tracker

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed WHOOP API helper that reads fitness and profile data, with manageable risks around local OAuth secret storage and dependency installation.

Install only if you are comfortable granting read access to WHOOP health, workout, sleep, recovery, profile, and body-measurement data. Keep `~/.whoop/credentials.json` and `~/.whoop/token.json` private, avoid using this on shared machines, revoke tokens if exposed, and consider installing dependencies in a virtual environment with pinned packages.

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

T08 · Insecure Dependencies

Warning
Location
scripts/install.sh:5
Finding
Unpinned Third-Party Dependency Installation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/install.sh:5` **Related Location**: `SKILL.md:25-26`, `SKILL.md:167-169` **Vulnerability Type**: Unpinned and unverified package installation **Risk Level**: Medium ### Vulnerable Code ```bash pip3 install requests ``` ### Technical Analysis The installation script asks pip to install the latest version of `requests` without a version constraint, lockfile, package hash, explicit trusted index, or isolated virtual environment. The package source can be influenced by pip configuration files and environment variables such as `PIP_INDEX_URL` and `PIP_EXTRA_INDEX_URL`. Consequently, executing the installer may retrieve a package artifact that was not reviewed with this Skill. Installation may also modify the invoking user's global or user-level Python environment. The package name itself is legitimate and no malicious dependency is embedded in the repository. Exploitation therefore depends on an attacker compromising or influencing the configured package source, package release, DNS/network trust chain, or local pip configuration. ### Attack Path 1. An attacker compromises a configured Python package index or modifies the victim's pip configuration or environment. 2. The user or Agent executes `bash scripts/install.sh`. 3. `pip3 install requests` resolves an artifact without enforcing a reviewed version or cryptographic hash. 4. Pip downloads and installs the attacker-influenced artifact. 5. Malicious package installation or runtime code executes with the privileges of the user who invoked the installer. ### Impact Assessment Successful exploitation can result in arbitrary code execution under the invoking user's account. This may permit access to files available to that user, including `~/.whoop/credentials.json`, `~/.whoop/token.json`, and other user-owned data. If the installer is run with elevated privileges, the impact could extend to system-wide Python packages and privileged filesyste ...[truncated 158 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `requests` and all transitive dependencies to reviewed versions. 2. Generate a dependency lockfile containing cryptographic hashes. 3. Install with hash enforcement, for example: ```bash python3 -m pip install --require-hashes -r requirements.txt ``` 4. Use a dedicated virtual environment rather than modifying the global Python environment: ```bash python3 -m venv .venv .venv/bin/python -m pip install --require-hashes -r requirements.txt ``` 5. Document the expected package index and avoid automatically trusting indexes supplied through uncontrolled environment variables. 6. Periodically review and update pinned dependencies after security testing. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/whoop_client.py:67
Finding
Credential and OAuth Token Files Are Secured Only After Writing<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/whoop_client.py:67-77` - `SKILL.md:37-44` - `references/oauth.md:12-20` **Vulnerability Type**: Non-atomic secret-file creation with delayed permission hardening **Risk Level**: Low ### Vulnerable Code Token storage in `scripts/whoop_client.py:67-77`: ```python TOKEN_PATH.parent.mkdir(parents=True, exist_ok=True) now = datetime.now(timezone.utc) data = { "access_token": access_token, "refresh_token": refresh_token or self.refresh_token, "updated_at": now.isoformat(), "expires_at": (now + timedelta(seconds=expires_in)).isoformat(), } with open(TOKEN_PATH, "w") as f: json.dump(data, f, indent=2) os.chmod(TOKEN_PATH, 0o600) ``` Credential setup in `SKILL.md:37-44`: ```bash mkdir -p ~/.whoop cat > ~/.whoop/credentials.json <<EOF { "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET" } EOF chmod 600 ~/.whoop/credentials.json ``` Equivalent credential setup in `references/oauth.md:12-20`: ```bash mkdir -p ~/.whoop cat > ~/.whoop/credentials.json <<EOF { "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET" } EOF chmod 600 ~/.whoop/credentials.json ``` ### Technical Analysis Both credential and token files are written before restrictive mode `0600` is explicitly applied. Their initial permissions are therefore determined by the process umask. With an unusually permissive umask, another local user may be able to read the file between its creation and the subsequent `chmod`. The Python code also opens the fixed token path through the standard `open()` API. It does not reject symbolic links, verify ownership, or write through an atomically replaced temporary file. If an attacker can modify the `~/.whoop` directory or pre-create the token path, the write may follow an attacker-controlled symbolic link. This issue requires a hostile multi-user environment, permissive filesystem conditions, or prior attacker access to the relevant director ...[truncated 1944 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the WHOOP configuration directory with mode `0700` and verify that it is owned by the current user. 2. Set restrictive permissions at file creation time rather than after writing. 3. Refuse to follow symbolic links when supported by the operating system. 4. Write tokens to a securely created temporary file in the same directory, flush and synchronize it, and atomically replace the destination. 5. Verify ownership and file type before reading existing credential or token files. 6. Update setup documentation to establish a restrictive umask before creating credentials: ```bash umask 077 mkdir -p ~/.whoop chmod 700 ~/.whoop cat > ~/.whoop/credentials.json <<EOF { "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET" } EOF ``` 7. In Python, use a securely opened descriptor with mode `0600`, such as `os.open()` with `O_CREAT`, `O_WRONLY`, and `O_NOFOLLOW` where available. Use an atomic temporary-file replacement strategy to avoid partial or redirected writes. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (44)

Credential Access

High
Category
Privilege Escalation
Content
### 2. Save Credentials
```bash
mkdir -p ~/.whoop
cat > ~/.whoop/credentials.json <<EOF
{
  "client_id": "YOUR_CLIENT_ID",
  "client_secret": "YOUR_CLIENT_SECRET"
Confidence
87% confidence
Finding
The documentation directs users to place a client secret in a plaintext file under the home directory. Even with restrictive file permissions, plaintext secret storage creates credential exposure risk through backups, accidental sharing, local compromise, or other tools reading the file.

Credential Access

High
Category
Privilege Escalation
Content
## Error Responses

### 401 Unauthorized
Access token is invalid or expired. Refresh the token.

### 429 Too Many Requests
Rate limit exceeded. Check `Retry-After` header.
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
2. **Save credentials locally**:
   ```bash
   mkdir -p ~/.whoop
   cat > ~/.whoop/credentials.json <<EOF
   {
     "client_id": "YOUR_CLIENT_ID",
     "client_secret": "YOUR_CLIENT_SECRET"
Confidence
83% confidence
Finding
The documentation instructs users to store a client secret in plaintext in `~/.whoop/credentials.json`. Even with local permissions, plaintext secret storage increases the risk of credential disclosure through local compromise, backups, accidental sharing, or insecure endpoint environments.

Credential Access

High
Category
Privilege Escalation
Content
"client_secret": "YOUR_CLIENT_SECRET"
   }
   EOF
   chmod 600 ~/.whoop/credentials.json
   ```

## Authorization Flow
Confidence
81% confidence
Finding
This step finalizes creation of a local credentials file containing the client secret, confirming persistent plaintext secret storage on disk. While common in developer examples, this still expands the attack surface for secret theft from the user's machine.

Credential Access

High
Category
Privilege Escalation
Content
```

This exchanges the code for:
- **Access token**: Used for API requests (expires after ~1 hour)
- **Refresh token**: Used to get new access tokens

Tokens are automatically saved to `~/.whoop/token.json`.
Confidence
87% confidence
Finding
The documentation states that access and refresh tokens are automatically saved to `~/.whoop/token.json`, meaning bearer credentials are persisted locally. Refresh tokens are especially sensitive because theft can allow long-lived unauthorized API access until revocation or expiry.

Credential Access

High
Category
Privilege Escalation
Content
This exchanges the code for:
- **Access token**: Used for API requests (expires after ~1 hour)
- **Refresh token**: Used to get new access tokens

Tokens are automatically saved to `~/.whoop/token.json`.
Confidence
86% confidence
Finding
This finding reflects the same behavior: storage and reuse of bearer tokens capable of authenticating to the WHOOP API. Persisting such tokens without stronger safeguards increases the risk of account data exposure if the local environment is compromised.

Credential Access

High
Category
Privilege Escalation
Content
### Automatic Refresh

The `WhoopClient` automatically refreshes expired access tokens using the refresh token when a 401 response is received.

### Manual Refresh
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
## Troubleshooting

### "Credentials not found"
Create `~/.whoop/credentials.json` with your client_id and client_secret.

### "Not authenticated"
Run `client.authenticate(code)` with a valid authorization code first.
Confidence
76% confidence
Finding
The troubleshooting section reinforces storing `client_id` and `client_secret` in a local plaintext file, normalizing a weaker secret-management practice. Repetition in docs can lead users to adopt insecure long-term storage without considering safer alternatives.

Credential Access

High
Category
Privilege Escalation
Content
- Never commit credentials or tokens to version control
- Store credentials with restricted permissions (`chmod 600`)
- Refresh tokens are long-lived but can be revoked by the user
- Access tokens expire after ~1 hour and must be refreshed
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
echo "  1. Register an app at https://developer.whoop.com"
echo "  2. Create credentials file:"
echo "     mkdir -p ~/.whoop"
echo '     echo '"'"'{"client_id": "YOUR_ID", "client_secret": "YOUR_SECRET"}'"'"' > ~/.whoop/credentials.json'
echo "     chmod 600 ~/.whoop/credentials.json"
echo ""
echo "  3. Complete OAuth authorization (see references/oauth.md)"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
echo "  1. Register an app at https://developer.whoop.com"
echo "  2. Create credentials file:"
echo "     mkdir -p ~/.whoop"
echo '     echo '"'"'{"client_id": "YOUR_ID", "client_secret": "YOUR_SECRET"}'"'"' > ~/.whoop/credentials.json'
echo "     chmod 600 ~/.whoop/credentials.json"
echo ""
echo "  3. Complete OAuth authorization (see references/oauth.md)"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
echo "  1. Register an app at https://developer.whoop.com"
echo "  2. Create credentials file:"
echo "     mkdir -p ~/.whoop"
echo '     echo '"'"'{"client_id": "YOUR_ID", "client_secret": "YOUR_SECRET"}'"'"' > ~/.whoop/credentials.json'
echo "     chmod 600 ~/.whoop/credentials.json"
echo ""
echo "  3. Complete OAuth authorization (see references/oauth.md)"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
echo "  1. Register an app at https://developer.whoop.com"
echo "  2. Create credentials file:"
echo "     mkdir -p ~/.whoop"
echo '     echo '"'"'{"client_id": "YOUR_ID", "client_secret": "YOUR_SECRET"}'"'"' > ~/.whoop/credentials.json'
echo "     chmod 600 ~/.whoop/credentials.json"
echo ""
echo "  3. Complete OAuth authorization (see references/oauth.md)"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
echo "  1. Register an app at https://developer.whoop.com"
echo "  2. Create credentials file:"
echo "     mkdir -p ~/.whoop"
echo '     echo '"'"'{"client_id": "YOUR_ID", "client_secret": "YOUR_SECRET"}'"'"' > ~/.whoop/credentials.json'
echo "     chmod 600 ~/.whoop/credentials.json"
echo ""
echo "  3. Complete OAuth authorization (see references/oauth.md)"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
echo "  1. Register an app at https://developer.whoop.com"
echo "  2. Create credentials file:"
echo "     mkdir -p ~/.whoop"
echo '     echo '"'"'{"client_id": "YOUR_ID", "client_secret": "YOUR_SECRET"}'"'"' > ~/.whoop/credentials.json'
echo "     chmod 600 ~/.whoop/credentials.json"
echo ""
echo "  3. Complete OAuth authorization (see references/oauth.md)"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
echo "  1. Register an app at https://developer.whoop.com"
echo "  2. Create credentials file:"
echo "     mkdir -p ~/.whoop"
echo '     echo '"'"'{"client_id": "YOUR_ID", "client_secret": "YOUR_SECRET"}'"'"' > ~/.whoop/credentials.json'
echo "     chmod 600 ~/.whoop/credentials.json"
echo ""
echo "  3. Complete OAuth authorization (see references/oauth.md)"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
echo "  1. Register an app at https://developer.whoop.com"
echo "  2. Create credentials file:"
echo "     mkdir -p ~/.whoop"
echo '     echo '"'"'{"client_id": "YOUR_ID", "client_secret": "YOUR_SECRET"}'"'"' > ~/.whoop/credentials.json'
echo "     chmod 600 ~/.whoop/credentials.json"
echo ""
echo "  3. Complete OAuth authorization (see references/oauth.md)"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
echo "  1. Register an app at https://developer.whoop.com"
echo "  2. Create credentials file:"
echo "     mkdir -p ~/.whoop"
echo '     echo '"'"'{"client_id": "YOUR_ID", "client_secret": "YOUR_SECRET"}'"'"' > ~/.whoop/credentials.json'
echo "     chmod 600 ~/.whoop/credentials.json"
echo ""
echo "  3. Complete OAuth authorization (see references/oauth.md)"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
echo "  1. Register an app at https://developer.whoop.com"
echo "  2. Create credentials file:"
echo "     mkdir -p ~/.whoop"
echo '     echo '"'"'{"client_id": "YOUR_ID", "client_secret": "YOUR_SECRET"}'"'"' > ~/.whoop/credentials.json'
echo "     chmod 600 ~/.whoop/credentials.json"
echo ""
echo "  3. Complete OAuth authorization (see references/oauth.md)"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
echo "  1. Register an app at https://developer.whoop.com"
echo "  2. Create credentials file:"
echo "     mkdir -p ~/.whoop"
echo '     echo '"'"'{"client_id": "YOUR_ID", "client_secret": "YOUR_SECRET"}'"'"' > ~/.whoop/credentials.json'
echo "     chmod 600 ~/.whoop/credentials.json"
echo ""
echo "  3. Complete OAuth authorization (see references/oauth.md)"
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
self.refresh_token = refresh_token

    def _is_token_expired(self) -> bool:
        """Check if the access token is expired or about to expire."""
        if not self.token_expires_at:
            return False
        # Treat as expired 60 seconds before actual expiry
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
self.refresh_token = refresh_token

    def _is_token_expired(self) -> bool:
        """Check if the access token is expired or about to expire."""
        if not self.token_expires_at:
            return False
        # Treat as expired 60 seconds before actual expiry
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
self.refresh_token = refresh_token

    def _is_token_expired(self) -> bool:
        """Check if the access token is expired or about to expire."""
        if not self.token_expires_at:
            return False
        # Treat as expired 60 seconds before actual expiry
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
self.refresh_token = refresh_token

    def _is_token_expired(self) -> bool:
        """Check if the access token is expired or about to expire."""
        if not self.token_expires_at:
            return False
        # Treat as expired 60 seconds before actual expiry
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Session Persistence

Medium
Category
Rogue Agent
Content
```markdown
1. **Register Application**:
   - Go to https://developer.whoop.com
   - Create new app, get `client_id` and `client_secret`
   - Set redirect URI (e.g., `http://localhost:8080/callback`)

2. **Save Credentials**:
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.

Static analysis

No suspicious patterns detected.