T09 · Insecure Skill Coding Practices
- Location
scripts/credential_store.py:20- Finding
Credential encryption relies on predictable machine metadata
- Content
View full analysis
bytes: username = getpass.getuser() hostname = socket.gethostname() material = f"{hostname}:{username}{KEY_MATERIAL_SUFFIX}".encode("utf-8") return hashlib.scrypt( material, salt=SCRYPT_SALT, n=2**14, r=8, p=1, dklen=32, ) ``` The equivalent Node.js implementation is: ```javascript export const SCRYPT_SALT = 'insentek-skill-salt-v1'; const KEY_MATERIAL_SUFFIX = ':insentek-openapi-skill'; function deriveKeyMaterial() { const { username } = os.userInfo(); return `${os.hostname()}:${username}${KEY_MATERIAL_SUFFIX}`; } function deriveKey() { return crypto.scryptSync(deriveKeyMaterial(), SCRYPT_SALT, 32); } ``` ### Technical Analysis Although the stored fields use authenticated AES-256-GCM encryption, the encryption key is derived solely from: - The local username - The local hostname - A hardcoded suffix - A hardcoded scrypt salt None of these values constitutes a secret. A party that obtains `credentials.json` can reproduce the key if the username and hostname are known or guessed. These values are often exposed in backups, prompts, logs, inventory systems, device names, or other files on the same host. The use of scrypt increases the computational cost of guessing, but it does not compensate for the low entropy and predictability of the source material. File mode `0600` reduces access by other local users but does not protect copied backups, accidentally exposed archives, or files obtained through another compromised process running as the user. The hostname acce ...[truncated 1245 chars]- Remediation
View remediation
