T09 · Insecure Skill Coding Practices
Warning
- Location
- src/crypto_utils.py:7
- Finding
- API Credentials Are Protected with a Public, Deterministic Encryption Key<![CDATA[ ## Vulnerability Details **File Location**: `src/crypto_utils.py:7-31` **Vulnerability Type**: Hardcoded cryptographic secret and insecure credential storage **Risk Level**: Medium ### Vulnerable Code ```python class CryptoUtils: def __init__(self, password="Xtranslate_Secret_Key"): # 生成基于密码的固定密钥(也可以生成一个文件保存,但由于是本地工具,固定算法比较方便) salt = b'xtranslate_salt' kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100000, ) key = base64.urlsafe_b64encode(kdf.derive(password.encode())) self.fernet = Fernet(key) def encrypt(self, text): if not text: return "" return self.fernet.encrypt(text.encode()).decode() def decrypt(self, encrypted_text): if not encrypted_text or not encrypted_text.startswith("gAAAA"): # Fernet 密文特征 return encrypted_text # 如果不是加密文本,直接返回原文(兼容未加密的旧配置) try: return self.fernet.decrypt(encrypted_text.encode()).decode() except: return encrypted_text # 解密失败则返回原样 ``` ### Technical Analysis The application derives its Fernet key from the hardcoded password `Xtranslate_Secret_Key` and the hardcoded salt `xtranslate_salt`. Because both inputs are included in the distributed source code, every installation derives the same encryption key. PBKDF2's iteration count does not provide meaningful protection when the password and salt are already known. Anyone who obtains an encrypted API-key token can reproduce the key derivation process and decrypt the credential. The `decrypt` method also fails open. If a value is not recognized as Fernet ciphertext, or if decryption fails, the method returns the original value and downstream code treats it as a plaintext API key. This behavior can conceal configuration corruption and defeats strict validation of protected credentials. ### Attack Path 1. A user enters an API key through the GUI. ...[truncated 1078 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove the hardcoded password and salt from the source code. 2. Store API keys directly in an operating-system credential facility, such as Windows Credential Manager, macOS Keychain, or Linux Secret Service. 3. For headless deployments, use a dedicated secret manager or require credentials to be supplied through a protected runtime environment. 4. If local encryption is unavoidable: - Generate a cryptographically random, unique key for each installation. - Store the key separately from encrypted credentials. - Restrict the key file to the owning user. - Avoid placing the key or encrypted credentials in the project directory. 5. Make decryption fail closed. Invalid ciphertext should raise a specific exception rather than being returned as a possible plaintext key. 6. Do not infer encryption solely from the `gAAAA` prefix. Store explicit format and version metadata. 7. Rotate any API key whose encrypted value may have been exposed, because existing values can be decrypted using the published constants. ]]>
