T09 · Insecure Skill Coding Practices
Error
- Location
- src/cli.ts:13
- Finding
- Secret Key Stored in Plaintext and Exposed Through CLI Output## Vulnerability Details **File Location**: `src/cli.ts:13-33`; `src/storage.ts:33-37` **Vulnerability Type**: Plaintext credential storage and disclosure **Risk Level**: High ### Vulnerable Code `src/storage.ts:33-37`: ```ts export const saveKey = async (api: OpenClawPluginApi, key: string) => { const keyPath = getKeyPath(api); await fs.mkdir(path.dirname(keyPath), { recursive: true }); await fs.writeFile(keyPath, key, "utf-8"); }; ``` `src/cli.ts:13-33`: ```ts omni .command("status") .description("Show current Secret Key and blacklisted skills") .action(async () => { const keyPath = getKeyPath(api); let keyContent = "❌ NO SECRET KEY SAVED"; try { keyContent = await fs.readFile(keyPath, "utf-8"); } catch (e) { // File doesn't exist yet } const blacklist = await getInterceptedTools(api); console.log("\n" + "=".repeat(50)); console.log("📂 OMNIPERMISSION CONFIGURATION"); console.log("-".repeat(50)); console.log(`🔑 SECRET KEY:\n${keyContent.trim() || "Empty"}`); console.log("-".repeat(50)); console.log( `🚫 BLACKLISTED SKILLS: ${blacklist.length > 0 ? blacklist.join(", ") : "None (Pass-through mode)"}`, ); ``` ### Technical Analysis The OmniPersona authentication secret is written directly to `omni_key.txt` without encryption or an explicitly restrictive file mode. The effective permissions consequently depend on the process umask and surrounding state-directory permissions. More critically, the `status` command reads the credential and prints its complete value to standard output. This creates additional disclosure channels, including terminal capture, automated logs, support bundles, agent transcripts, and command-execution interfaces exposed to less-trusted users or agents. The project documentation explicitly discusses deployments where an agent can access the OpenClaw CLI. In such a deploy ...[truncated 1322 chars]
- Remediation
- ## Remediation Suggestions 1. Remove the full secret from the `status` command. Display only a masked value or short non-sensitive fingerprint, such as the final four characters. 2. Store the credential in an operating-system credential manager or secret-management service where available. 3. If file storage is unavoidable, create the file with mode `0o600` and verify or repair the permissions of existing files: ```ts await fs.writeFile(keyPath, key, { encoding: "utf-8", mode: 0o600, }); await fs.chmod(keyPath, 0o600); ``` 4. Ensure the containing state directory is accessible only to the OpenClaw service account. 5. Prevent secrets from appearing in application logs, CLI diagnostics, error messages, support bundles, and agent-visible command output. 6. Rotate credentials that may already have been exposed through `omnipermission status`.
