T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/polymarket.py:548
- Finding
- Polygon Private Key Stored in Plaintext and Entered Through an Echoing Prompt## Vulnerability Details **File Location**: `scripts/polymarket.py:548-562` **Vulnerability Type**: Plaintext storage and insecure collection of sensitive wallet credentials **Risk Level**: High ### Vulnerable Code ```python pk = input(" Enter your Polygon private key (hex): ").strip() if not pk: print(" Aborted.") return # Remove 0x prefix if present if pk.startswith("0x"): pk = pk[2:] WALLET_PATH.parent.mkdir(parents=True, exist_ok=True) config = {"private_key": pk} with open(WALLET_PATH, "w") as f: json.dump(config, f, indent=2) os.chmod(WALLET_PATH, 0o600) ``` The stored credential is subsequently loaded in full by the following helper at `scripts/polymarket.py:529-535`: ```python def _load_wallet(): """Load wallet config.""" if not WALLET_PATH.exists(): print("No wallet configured. Run: python3 polymarket.py wallet-setup", file=sys.stderr) sys.exit(1) with open(WALLET_PATH) as f: return json.load(f) ``` ### Technical Analysis The wallet setup command collects a Polygon private key using `input()`. Terminal input is therefore displayed while the user types, exposing the key to shoulder surfing, terminal recording, screen sharing, and captured console sessions. The key is then serialized without encryption to `~/.config/polymarket/wallet.json`. Setting the completed file to mode `0600` restricts access by other local user accounts, but it does not protect the key from: - Malicious or compromised processes running under the same user account. - Filesystem, workstation, or user-account compromise. - Backup, synchronization, snapshot, or diagnostic systems that capture the file. - Exposure during the interval between file creation and the subsequent `chmod`. - Accidental disclosure through copying or support collection. The implementation also loads the complete wallet object for placeholder commands such as `balance` and a ...[truncated 1980 chars]
- Remediation
- ## Remediation Suggestions 1. **Do not store raw private keys in plaintext.** Prefer a hardware wallet, external signer, OS credential manager, or encrypted keystore using a well-reviewed wallet library. 2. **Use hidden credential entry.** Replace `input()` with `getpass.getpass()` so the private key is not echoed: ```python from getpass import getpass pk = getpass(" Enter your Polygon private key (hex): ").strip() ``` 3. **Separate public identity from signing credentials.** Store only the public wallet address in ordinary configuration. Retrieve private signing material only when an operation actually requires a signature. 4. **Remove unnecessary wallet loading.** The placeholder `balance` and `orders` commands should not call `_load_wallet()` merely to establish that configuration exists. They should load a public-address-only configuration or request an address explicitly. 5. **Create sensitive files atomically with restrictive permissions.** If a local encrypted keystore is retained, create it with mode `0600` from the outset rather than applying permissions only after writing. 6. **Minimize secret lifetime in memory.** Load signing credentials immediately before signing, avoid logging or copying them, and release references as soon as practical. 7. **Validate imported key material safely.** Use a trusted wallet library to validate and derive the corresponding public address without printing or transmitting the private key. 8. **Document migration and rotation.** Existing users should move funds to a newly generated key if they believe the plaintext file or visible setup session may have been exposed, then securely delete the old credential file and affected backups.
