T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/setup_model.py:163
- Finding
- Plaintext API Key Exposure Through Command-Line Arguments, Visible Input, and Program Output<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup_model.py:163-175, 215-231`; `SKILL.md:33-38, 107-113` **Vulnerability Type**: Plaintext credential exposure **Risk Level**: Medium ### Vulnerable Code The interactive workflow reads the API key with ordinary visible terminal input and subsequently prints it as part of the generated JSON: ```python api_key = input("Enter API key: ").strip() if not api_key: print("❌ API key is required") return patch = generate_patch(provider_id, api_key) if patch: print("\n" + "=" * 60) print("📝 OpenClaw config.patch JSON:") print("=" * 60) print(json.dumps(patch, indent=2, ensure_ascii=False)) ``` The direct workflow obtains the key from a command-line argument and also prints the resulting configuration containing the plaintext key: ```python for i, arg in enumerate(args): if arg == "--provider" and i + 1 < len(args): provider_id = args[i + 1] elif arg == "--api-key" and i + 1 < len(args): api_key = args[i + 1] elif arg == "--model" and i + 1 < len(args): model_ids.append(args[i + 1]) if not provider_id: print("❌ --provider is required", file=sys.stderr) sys.exit(1) if not api_key: print("❌ --api-key is required", file=sys.stderr) sys.exit(1) patch = generate_patch(provider_id, api_key, model_ids or None) if patch: print(json.dumps(patch, indent=2, ensure_ascii=False)) ``` The documented workflow explicitly encourages users to place the secret in a command-line argument: ```bash python <skill-dir>/scripts/setup_model.py --provider deepseek --api-key sk-xxx ``` ### Technical Analysis API keys are authentication credentials and should not be exposed through process arguments, visible terminal entry, or routine output. Passing a key through `--api-key` can persist it in shell history. Depending on the operating system and process isolation settings, it may also be visible to process-monitoring utilities, diagnostic too ...[truncated 2298 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Remove command-line secret handling by default** - Deprecate `--api-key <value>`. - Accept the key through a protected environment variable, standard input, an inherited file descriptor, or an operating-system credential store. - If compatibility requires the option temporarily, display a prominent warning that it can expose the key through shell history and process inspection. 2. **Conceal interactive credential entry** - Replace ordinary terminal input with hidden input: ```python from getpass import getpass api_key = getpass("Enter API key: ").strip() ``` 3. **Do not print complete credentials** - Avoid emitting a patch containing the real `apiKey` to standard output. - Pass the patch directly to the trusted configuration API through an in-memory channel where supported. - If output is necessary, print a redacted representation such as `"apiKey": "********"` and provide the secret separately through a protected channel. 4. **Reduce accidental logging** - Ensure errors and debug output never include the key. - Document that generated configuration and transcripts are sensitive. - Disable or sanitize command tracing and application logging around secret processing. 5. **Update documentation** - Replace examples using `--api-key sk-xxx` with a secure workflow. - Explain the risks of shell history, process arguments, terminal scrollback, redirected output, and agent transcripts. - Do not imply that encrypted storage protects credentials before they reach the storage layer. 6. **Operational response** - Advise users who have already used the existing workflow to inspect and remove affected shell history and logs where feasible. - Rotate any API key that may have appeared in process arguments, terminal recordings, generated output, or agent transcripts. ]]>
