T09 · Insecure Skill Coding Practices
- Location
bin/setup.py:43- Finding
Wallet Private Key Stored in Plaintext Without Enforced File Permissions
- Content
View full analysis
None: CONFIG_DIR.mkdir(parents=True, exist_ok=True) CONFIG_FILE.write_text(json.dumps(cfg, indent=2) + "\n") ``` ```python def cmd_generate_wallet(_args) -> int: address, pk = generate_wallet() cfg = _load_config() cfg["wallet_address"] = address cfg["wallet_private_key"] = pk # in production: vault; here config _save_config(cfg) _emit({"address": address, "saved_to": str(CONFIG_FILE)}) return 0 ``` ### Technical Analysis Reporter-mode wallet generation stores the Ethereum private key directly in `~/.openclaw/phishing-detection/config.json`. The implementation does not explicitly create the configuration directory with mode `0700` or the file with mode `0600`. Consequently, actual access depends on the process umask, existing directory permissions, backup configuration, and other local environmental controls. The source acknowledges that a production deployment should use a vault, but the active implementation still uses persistent plaintext storage. The private key is a bearer credential: possession is sufficient to authorize transactions independently of this project. Although `RegistryClient` only exposes selected registry operations, this restriction does not protect a private key after it is copied. An attacker can import the key into unrelated Ethereum software and sign arbitrary transactions. ### Attack Path 1. The user selects Reporter mode. 2. `cmd_generate_wallet()` creates a new Ethereum private key. 3. `_save_config()` serializes the key into `config.json` using ambient filesystem permissions. 4. Another local user, compromised process, backup agent, or overly broad file-indexing integration reads the file. 5. The attacker imports the private key int ...[truncated 564 chars]- Remediation
View remediation
