T08 · Insecure Dependencies
- Location
scripts/install.sh:5- Finding
Unpinned Third-Party Dependency Installation
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
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.
scripts/install.sh:5Unpinned Third-Party Dependency Installation
scripts/whoop_client.py:67Credential and OAuth Token Files Are Secured Only After Writing
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.
mkdir -p ~/.whoop
cat > ~/.whoop/credentials.json <<EOF
{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
## Error Responses
### 401 Unauthorized
Access token is invalid or expired. Refresh the token.
### 429 Too Many Requests
Rate limit exceeded. Check `Retry-After` header.
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.
mkdir -p ~/.whoop
cat > ~/.whoop/credentials.json <<EOF
{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET"
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.
"client_secret": "YOUR_CLIENT_SECRET" } EOF chmod 600 ~/.whoop/credentials.json
## Authorization Flow
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.
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`.
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.
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`.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
### Automatic Refresh
The `WhoopClient` automatically refreshes expired access tokens using the refresh token when a 401 response is received.
### Manual Refresh
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.
## 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.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
- 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
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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)"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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)"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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)"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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)"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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)"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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)"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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)"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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)"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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)"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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)"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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)"
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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
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.
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**:
No suspicious patterns detected.