T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/openclaw_to_hermes.py:924
- Finding
- Secret migration controls are bypassed for Discord and Slack tokens<![CDATA[ ## Vulnerability Details **File Location**: `scripts/openclaw_to_hermes.py:924-959` (preset inclusion also occurs at lines 118-139) **Vulnerability Type**: Secret migration without explicit authorization **Risk Level**: High ### Complete Code Snippet ```python def migrate_discord_settings(self, config: Optional[Dict[str, Any]] = None) -> None: config = config or self.load_openclaw_config() additions: Dict[str, str] = {} discord = config.get("channels", {}).get("discord", {}) if isinstance(discord, dict): token = discord.get("token") if isinstance(token, str) and token.strip(): additions["DISCORD_BOT_TOKEN"] = token.strip() allow_from = discord.get("allowFrom", []) if isinstance(allow_from, list): users = [str(u).strip() for u in allow_from if str(u).strip()] if users: additions["DISCORD_ALLOWED_USERS"] = ",".join(users) if additions: self.merge_env_values( additions, "discord-settings", self.source_root / "openclaw.json", ) else: self.record( "discord-settings", self.source_root / "openclaw.json", self.target_root / ".env", "skipped", "No Discord settings found", ) def migrate_slack_settings(self, config: Optional[Dict[str, Any]] = None) -> None: config = config or self.load_openclaw_config() additions: Dict[str, str] = {} slack = config.get("channels", {}).get("slack", {}) if isinstance(slack, dict): bot_token = slack.get("botToken") if isinstance(bot_token, str) and bot_token.strip(): additions["SLACK_BOT_TOKEN"] = bot_token.strip() app_token = slack.get("appToken") if isinstance(app_token, str) and app_token.strip(): additions["SLACK_APP_TOKEN"] = app_token.strip() allow_from = slack.get("allowFrom", []) if isinstance(allow_from ...[truncated 2161 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require `self.migrate_secrets` before extracting or writing every token: ```python if self.migrate_secrets: token = discord.get("token") if isinstance(token, str) and token.strip(): additions["DISCORD_BOT_TOKEN"] = token.strip() ``` 2. Separate non-secret channel settings from token migration so allowlists can still be migrated under `user-data`. 3. Remove token-bearing groups from the `user-data` preset, or split them into groups such as `discord-settings` and `discord-secret-settings`. 4. Maintain a single centralized allowlist of secret source fields and destination variables. 5. Add tests verifying that `--preset user-data` never modifies token-related environment variables. 6. Update `SKILL.md` so the documented secret allowlist exactly matches implementation behavior. ]]>
