T09 · Insecure Skill Coding Practices
- Location
scripts/bookmark-poll.js:33- Finding
OAuth token cache may be created with overly permissive filesystem permissions
- Content
View full analysis
Vulnerability Details
File Location:
scripts/bookmark-poll.js:33-38; duplicate vulnerable write atscripts/backlog-sweep.js:94-95
Vulnerability Type: Sensitive credential storage with permissions inherited from the process umask
Risk Level: HighVulnerable Code
scripts/bookmark-poll.js:33-38:js function saveTokenCache(data) { fs.mkdirSync(path.dirname(TOKEN_CACHE), { recursive: true }); fs.writeFileSync(TOKEN_CACHE, JSON.stringify({ ...data, cached_at: Date.now() }, null, 2)); }scripts/backlog-sweep.js:94-95:js fs.mkdirSync(path.dirname(TOKEN_CACHE), { recursive: true }); fs.writeFileSync(TOKEN_CACHE, JSON.stringify({ ...data, cached_at: Date.now() }, null, 2));Technical Analysis
Both scripts persist the complete OAuth token response to
data/x-oauth2-token-cache.jsonwithout specifying a restrictive file mode. The response contains an X access token and may also contain a refresh token. When the cache file is first created, its permissions are determined by the process umask. Under a common022umask, the resulting file may be readable by other local users.This behavior contradicts the security claim in
README.mdthat OAuth tokens are stored with mode0o600. Althoughscripts/x-oauth2-authorize.jsand the rotated-token write explicitly use0o600, subsequent cache creation in these two polling scripts does not provide the same protection.If the file already exists with insecure permissions, adding a mode only to later writes is insufficient because opening an existing file does not necessarily replace its mode. Existing cache files must also be explicitly repaired.
Attack Path
- A user configures valid X OAuth credentials and runs
bookmark-poll.jsorbacklog-sweep.js. - No token cache currently exists, so the script creates
data/x-oauth2-token-cache.json. - The process uses a permissive umask, causing the file t ...[truncated 1112 chars]
- A user configures valid X OAuth credentials and runs
- Remediation
View remediation
Remediation Suggestions
-
Create the data directory with owner-only permissions and explicitly set token files to
0o600:js function saveTokenCache(data) { fs.mkdirSync(path.dirname(TOKEN_CACHE), { recursive: true, mode: 0o700 }); fs.writeFileSync( TOKEN_CACHE, JSON.stringify({ ...data, cached_at: Date.now() }, null, 2), { mode: 0o600 } ); fs.chmodSync(TOKEN_CACHE, 0o600); } -
Apply the same correction in
backlog-sweep.js. -
Repair existing installations during startup by checking and resetting the cache mode with
fs.chmodSync. -
Prefer atomic credential writes: write to a randomly named owner-only file in the same directory, call
fsync, set mode0o600, and rename it over the destination. -
Store refresh tokens in an operating-system credential store or dedicated secrets manager where practical.
-
Add a setup check that rejects or warns about token files readable by group or other users.
-
Update documentation so its
0o600claim is verified by all token-writing paths.
-
