T09 · Insecure Skill Coding Practices
- Location
src/utils/api-key.js:46- Finding
API Key Stored Without Restrictive File Permissions
- Content
View full analysis
Vulnerability Details
File Location:
src/utils/api-key.js, lines 46-52
Vulnerability Type: Plaintext credential storage with insufficient file-permission hardening
Risk Level: MediumVulnerable Code
javascript if (!fs.existsSync(CONFIG_DIR)) { fs.mkdirSync(CONFIG_DIR, { recursive: true }); } const trimmedKey = apiKey.trim(); fs.writeFileSync(API_KEY_FILE, JSON.stringify({ jupiterApiKey: trimmedKey }, null, 2)); return trimmedKey;Technical Analysis
ApiKeyManager.setApiKey()stores the Jupiter API key as plaintext inconfig/api-key.json. Neither the directory nor the file is created with an explicit restrictive mode. Their effective permissions therefore depend on the process umask. Under a common0022umask, the directory may be created as0755and the file as0644, allowing other local users to read the credential.The code also checks only whether the path exists before writing it. It does not reject symbolic links or use exclusive, no-follow file creation. If an attacker who can write to the working directory prepares
config/api-key.jsonas a symbolic link, the subsequent write may follow that link. Exploitability of this symlink scenario depends on the attacker already having suitable filesystem access and on operating-system protections.Attack Path
- A victim runs the application from a directory accessible to another local user and calls
JupiterPredictionClient.setApiKey()orApiKeyManager.setApiKey(). - The method creates
config/api-key.jsonusing ambient umask-derived permissions and writes the API key in plaintext. - If the resulting file is group- or world-readable, another local user reads it directly.
- Alternatively, where the attacker can modify the working directory beforehand, the attacker creates a malicious symbolic link at
config/api-key.json; the application follows it when writing. - The attacker obtains the Jupiter API key and submits authenticated requests to the Jupi ...[truncated 768 chars]
- A victim runs the application from a directory accessible to another local user and calls
- Remediation
View remediation
Remediation Suggestions
- Create the configuration directory with owner-only permissions:
javascript fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 }); fs.chmodSync(CONFIG_DIR, 0o700);- Write the key file with mode
0600. Prefer exclusive creation and an atomic replacement strategy that does not follow attacker-controlled symbolic links. - Before updating an existing path, inspect it with
fs.lstatSync()and reject symbolic links or non-regular files. - Open files using restrictive flags and permissions, such as
O_WRONLY | O_CREAT | O_EXCLwhere appropriate. On supported systems, useO_NOFOLLOW. - If atomic updates are needed, securely create a temporary file in the protected directory with
0600, write and synchronize it, then rename it over a validated regular destination. - Apply
fs.chmodSync(API_KEY_FILE, 0o600)to securely migrate existing installations. - Prefer the
JUPITER_API_KEYenvironment variable or an operating-system credential store instead of persistent plaintext storage. - Document that the project must not be run from a shared or attacker-writable working directory.
