T09 · Insecure Skill Coding Practices
- Location
src/sparki_cli/config.py:45- Finding
API Key Stored in Plaintext Without Restrictive File Permissions
- Content
View full analysis
None: self.config_dir.mkdir(parents=True, exist_ok=True) if api_key is not None: self._data["api_key"] = api_key if base_url is not None: self._data["base_url"] = base_url elif "base_url" not in self._data: self._data["base_url"] = DEFAULT_BASE_URL if default_output_dir is not None: self._data["default_output_dir"] = default_output_dir self.config_file.write_text(json.dumps(self._data, indent=2)) ``` ### Technical Analysis The `save` method stores the Sparki API key directly in the JSON configuration file at `~/.openclaw/config/sparki.json`. The API key is not encrypted or protected through an operating-system credential store. The code also does not explicitly enforce owner-only permissions on either the configuration directory or the configuration file. `Path.mkdir()` and `Path.write_text()` rely on the process umask and any pre-existing filesystem permissions. In an environment with a permissive umask or an improperly permissioned pre-existing configuration directory, another local account may be able to read the credential. The method also does not verify whether `sparki.json` is a symbolic link before writing it, which weakens the integrity guarantees around credential storage. ### Attack Path 1. The user runs `sparki setup --api-key `. 2. The `Config.save()` method serializes the API key into `~/.openclaw/config/sparki.json`. 3. The file is created using permissions derived from the current process umask rather than an explicitly enforced `0600` mode. 4. Another local user or process with filesystem access reads the configuration file. 5. The attacker extra ...[truncated 635 chars]- Remediation
View remediation
