T09 · Insecure Skill Coding Practices
Warning
- Location
- lib/tokens.js:15
- Finding
- OAuth Tokens Persisted Without Restrictive File Permissions## Vulnerability Details **File Location**: `lib/tokens.js:15-18` **Related Documentation**: `SKILL.md:30-35`, `SKILL.md:47` **Vulnerability Type**: Plaintext sensitive data stored with umask-dependent permissions **Risk Level**: Medium ### Vulnerable Code ```js function writeTokens(tokens) { fs.mkdirSync(CACHE_DIR, { recursive: true }); fs.writeFileSync(TOKENS_PATH, JSON.stringify(tokens, null, 2) + '\n'); } ``` The related setup instructions also direct users to store credentials in a plaintext environment file without requiring restrictive permissions: ```markdown 3) Put secrets into `~/.clawdbot/.env`: ```bash WHOOP_CLIENT_ID=... WHOOP_CLIENT_SECRET=... ``` ``` The documentation further states: ```markdown This writes `WHOOP_REFRESH_TOKEN=...` into `~/.clawdbot/.env`. ``` ### Technical Analysis `writeTokens` serializes the complete OAuth token object into `tokens.json`. This object may include a WHOOP access token, refresh token, expiration metadata, and other OAuth response fields. Neither the cache directory nor the token file is created with an explicit restrictive mode. Node.js consequently creates the directory and file according to platform defaults modified by the process umask. For example, a permissive or typical umask may result in a token file readable by users other than its owner. Existing files with insecure permissions are also not corrected. The same concern applies to the documented `~/.clawdbot/.env` storage. It contains the client secret and refresh token, but the instructions do not tell users to create it with mode `0600` or otherwise protect it through a secret manager. Storing OAuth credentials locally is necessary for the declared WHOOP integration, especially because WHOOP rotates refresh tokens. However, making those credentials potentially accessible to unrelated local users exceeds the minimum access required. Only the account running the Skill should be ab ...[truncated 1755 chars]
- Remediation
- ## Remediation Suggestions 1. Create the cache directory with owner-only permissions: ```js fs.mkdirSync(CACHE_DIR, { recursive: true, mode: 0o700 }); fs.chmodSync(CACHE_DIR, 0o700); ``` 2. Write the token file with mode `0600` and correct permissions on existing files: ```js fs.writeFileSync( TOKENS_PATH, JSON.stringify(tokens, null, 2) + '\n', { mode: 0o600 } ); fs.chmodSync(TOKENS_PATH, 0o600); ``` 3. Use atomic replacement to reduce corruption and partial-write risks. Create a temporary file in the protected directory with mode `0600`, flush it, and rename it over the destination. 4. Before replacing existing credential files, verify that the destination is owned by the expected user and is not a symbolic link or unexpected file type. 5. Prefer an operating-system credential store or managed secret service instead of plaintext files where the execution environment supports one. 6. Update `SKILL.md` to require secure environment-file creation, for example: ```bash mkdir -p ~/.clawdbot chmod 700 ~/.clawdbot install -m 600 /dev/null ~/.clawdbot/.env ``` 7. Avoid printing access tokens, refresh tokens, client secrets, or full OAuth responses in command output or logs. 8. Document credential revocation and rotation procedures for users who suspect that either local file was exposed.
