T09 · Insecure Skill Coding Practices
- Location
scripts/progress_selfcheck_and_send.py:198- Finding
PowerShell Command Injection Through Report Content and Feishu Configuration
- Content
View full analysis
None: if not cfg.get("feishu", {}).get("enabled", True): return account = cfg["feishu"]["account"] target = cfg["feishu"]["target"] safe = message.replace("`", "``") ps = ( "$m = @'\n" + safe + "\n'@; " + f"openclaw message send --channel feishu --account {account} --target {target} --message \"$m\"" ) cmd = ["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", ps] workdir = Path(cfg["workdir"]) res = subprocess.run(cmd, cwd=str(workdir), capture_output=True, text=True, encoding="utf-8", errors="replace") ``` ### Technical Analysis The function constructs executable PowerShell source by concatenating report content and configuration values into a command string. Replacing backticks is not sufficient to secure a PowerShell single-quoted here-string. A line containing the here-string terminator `'@` can close `$m` before the intended boundary. Any text following that terminator can then be interpreted as PowerShell code. The `feishu.account` and `feishu.target` values are also inserted directly into the PowerShell command without quoting or strict validation. PowerShell metacharacters in either value can consequently alter the intended command. The generated report contains data read from several mutable sources: - Task titles and `next` commands from the task ledger - Progress-event messages - Cron job names and state - Feishu configuration values The relevant content is formatted into `message` in `scripts/progress_selfcheck_and_send.py`, lines 217-282, before being embedded in PowerShell source. Using `subprocess.run()` with an argument array does not prevent this vulnerability because PowerShell itself is explicitly i ...[truncated 1720 chars]- Remediation
View remediation
None: feishu = cfg.get("feishu", {}) if not feishu.get("enabled", True): return account = feishu["account"] target = feishu["target"] cmd = [ "openclaw", "message", "send", "--channel", "feishu", "--account", account, "--target", target, "--message", message, ] workdir = Path(cfg["workdir"]) res = subprocess.run( cmd, cwd=str(workdir), capture_output=True, text=True, encoding="utf-8", errors="replace", shell=False, timeout=60, ) if res.returncode != 0: raise SystemExit( f"openclaw message send failed rc={res.returncode}: " f"{res.stderr.strip() or res.stdout.strip()}" ) ``` Additional hardening should include: 1. Validate `account` against a narrow identifier pattern suitable for configured OpenClaw accounts. 2. Validate `target` against the expected Feishu target syntax, such as a strict `user:ou_...` format. 3. Reject control characters in account and target fields. 4. Apply length limits to report fields to prevent resource exhaustion. 5. Avoid logging full command errors if they may expose sensitive message content. 6. Run the scheduled job under a dedicated, least-privileged account. 7. Add regression tests containing PowerShell metacharacters, newlines, quotes, and the `'@` here-string terminator. ]]>
