T09 · Insecure Skill Coding Practices
- Location
scripts/poll-auth.js:27- Finding
Bearer Credential Stored Without Restrictive Filesystem Permissions
- Content
View full analysis
Vulnerability Details
File Location:
scripts/poll-auth.js:27-38,scripts/token-manager.js:105-113,scripts/utils.js:9-19, 41-43
Vulnerability Type: Plaintext sensitive credential storage with inherited default permissions
Risk Level: HighVulnerable Code
js async function saveAuthorizedToken(result) { const tokenRecord = { [AUTH_TOKEN_KEY]: result[AUTH_TOKEN_KEY], uid: result.uid || null, authType: result.authType ?? null, savedAt: new Date().toISOString(), }; await ensureDataDir(); await writeFile(TOKEN_FILE, JSON.stringify(tokenRecord, null, 2), "utf-8"); for (const filePath of TOKEN_FALLBACK_FILES) { try { await unlink(filePath); } catch { // file may not exist, that's fine } } }js const tokenRecord = { authToken: data.authToken, uid: data.uid || null, authType: data.authType ?? null, savedAt: new Date().toISOString(), }; await ensureDataDir(); await writeFile(TOKEN_FILE, JSON.stringify(tokenRecord, null, 2), "utf-8");js export const OPEN_HEALTH_LINK_DATA_DIR = join( SKILL_ROOT_DIR, ".open-health-link-data" ); export const TOKEN_FILE = join(OPEN_HEALTH_LINK_DATA_DIR, "token.json"); export async function ensureDataDir() { await mkdir(OPEN_HEALTH_LINK_DATA_DIR, { recursive: true }); }Technical Analysis
The authorization bearer credential is written as plaintext JSON. Neither directory creation nor file creation specifies a restrictive permission mode. Node.js therefore applies its normal defaults, subject to the process umask. Existing files can also retain previously permissive permissions when overwritten.
Because the credential authorizes access to private scalp-health information, it should be handled as a high-value secret. Storing it beneath the Skill installation directory can be particularly risky when the Skill is installed in a shared ...[truncated 1385 chars]
- Remediation
View remediation
Remediation Suggestions
- Create the credential directory with mode
0700. - Create or replace the credential file atomically with mode
0600. - Check existing file and directory permissions at startup and repair permissions that are too broad.
- Reject symbolic links and unexpected file types before reading or replacing the credential file.
- Prefer an operating-system credential manager or encrypted secret store instead of plaintext JSON.
- Apply the same validation to legacy fallback credential files before reading them.
- Document credential retention, revocation, and deletion behavior.
- Add automated tests that fail when the stored credential is readable by group or other users.
- Create the credential directory with mode
