T09 · Insecure Skill Coding Practices
- Location
scripts/configure-keyapi-auth.mjs:187- Finding
Bearer Token Is Exposed During Entry and Persisted in Plaintext
- Content
View full analysis
Vulnerability Details
File Location:
scripts/configure-keyapi-auth.mjs:187-211, 220-226
Vulnerability Type: Plaintext credential handling and insecure secret input
Risk Level: MediumVulnerable Code
js async function collectCredentials(args) { const token = args.token ? requireRealValue("KEYAPI_TOKEN", args.token) : undefined; if (token) { return { token }; } const rl = createInterface({ input, output }); try { output.write("KeyAPI setup will save KEYAPI_TOKEN into your shell environment variables.\n"); const enteredToken = await rl.question("Paste KEYAPI_TOKEN: "); return { token: requireRealValue("KEYAPI_TOKEN", enteredToken) }; } finally { rl.close(); } } function writeProfile(profilePath, credentials) { ensureParentDir(profilePath); const profileKind = detectProfileKind(profilePath); const existing = fs.existsSync(profilePath) ? fs.readFileSync(profilePath, "utf8") : ""; const cleaned = stripManagedBlock(existing); const block = buildManagedBlock(credentials, profileKind); const next = cleaned ? `${cleaned}\n\n${block}` : block; fs.writeFileSync(profilePath, next); return profileKind; }The token is embedded into the generated profile block:
js function buildManagedBlock(values, profileKind) { if (profileKind === "powershell") { return [ managedBlockStart, `$env:KEYAPI_TOKEN = ${powershellQuote(values.token)}`, managedBlockEnd, "" ].join("\n"); } return [ managedBlockStart, `export KEYAPI_TOKEN=${shellQuote(values.token)}`, managedBlockEnd, "" ].join("\n"); }The documentation also offers command-line token entry at
references/setup-and-auth.md:39-43:bash node scripts/configure-keyapi-auth.mjs --token "your_keyapi_token"Technical Analysis
The interactive setup reads
KEYAPI_TOKENthrough a normal readline prompt. Unlike a password-specific terminal input mechanism, this does not ...[truncated 2150 chars]- Remediation
View remediation
Remediation Suggestions
- Replace ordinary readline token collection with a secret-input implementation that disables terminal echo and reliably restores terminal settings on success, interruption, and error.
- Remove the
--tokenoption or mark it unsafe and deprecated. Prefer protected standard input, an OS credential manager, or another secret channel that does not place credentials in process arguments. - Store the token in the platform credential store where available, such as Windows Credential Manager, macOS Keychain, or a Linux Secret Service provider.
- If file-based storage is necessary, use a dedicated credential file rather than a general shell profile:
- Create it atomically with mode
0600on POSIX systems. - Verify that it is owned by the current user.
- Reject group- or world-readable permissions.
- Prevent symbolic-link and unsafe replacement attacks.
- Create it atomically with mode
- If shell-profile persistence remains supported, inspect ownership and permissions before reading or writing, preserve secure permissions, and warn the user explicitly that the token will be stored in plaintext.
- Remove the command-line token example from
references/setup-and-auth.mdand document the protected input mechanism instead. - Advise affected users to revoke and rotate tokens that may already have appeared in shell history, terminal recordings, or broadly accessible profile files.
