T09 · Insecure Skill Coding Practices
- Location
lib/tokens.js:15- Finding
OAuth Tokens Persisted Without Restrictive File Permissions
- Content
View full analysis
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: MediumVulnerable 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=...text The documentation further states: ```markdown This writes `WHOOP_REFRESH_TOKEN=...` into `~/.clawdbot/.env`.Technical Analysis
writeTokensserializes the complete OAuth token object intotokens.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/.envstorage. It contains the client secret and refresh token, but the instructions do not tell users to create it with mode0600or 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
View remediation
Remediation Suggestions
-
Create the cache directory with owner-only permissions:
js fs.mkdirSync(CACHE_DIR, { recursive: true, mode: 0o700 }); fs.chmodSync(CACHE_DIR, 0o700); -
Write the token file with mode
0600and correct permissions on existing files:js fs.writeFileSync( TOKENS_PATH, JSON.stringify(tokens, null, 2) + '\n', { mode: 0o600 } ); fs.chmodSync(TOKENS_PATH, 0o600); -
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. -
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.
-
Prefer an operating-system credential store or managed secret service instead of plaintext files where the execution environment supports one.
-
Update
SKILL.mdto require secure environment-file creation, for example:bash mkdir -p ~/.clawdbot chmod 700 ~/.clawdbot install -m 600 /dev/null ~/.clawdbot/.env -
Avoid printing access tokens, refresh tokens, client secrets, or full OAuth responses in command output or logs.
-
Document credential revocation and rotation procedures for users who suspect that either local file was exposed.
-
