T09 · Insecure Skill Coding Practices
- Location
- lib/automation.py:552
- Finding
- Safe Mode Can Be Bypassed Through Macro Playback<![CDATA[ ## Vulnerability Details **File Location**: `lib/automation.py:552-556`, `lib/safety.py:44-73`, `scripts/play_macro.py:82-154`, `scripts/play_macro.py:271-292` **Vulnerability Type**: Safety-control bypass through an unvalidated subprocess execution path **Risk Level**: High ### Vulnerable Code The main dispatcher validates only the top-level `play_macro` action and then launches a separate process: ```python def play_macro(macro_path, speed=1.0): script_dir = os.path.dirname(os.path.abspath(__file__)) player_script = os.path.join(script_dir, '..', 'scripts', 'play_macro.py') if not os.path.exists(player_script): return {"status": "error", "message": f"Player script not found: {player_script}"} if not os.path.exists(macro_path): return {"status": "error", "message": f"Macro file not found: {macro_path}"} try: subprocess.run([sys.executable, player_script, macro_path, str(speed)], check=True) return {"status": "ok"} except subprocess.CalledProcessError as e: return {"status": "error", "message": str(e)} except Exception as e: return {"status": "error", "message": str(e)} ``` The safety layer treats only action names containing selected risky-action strings as risky: ```python def validate_action(self, action: str, params: Dict[str, Any]) -> Dict[str, Any]: for param_key, values in params.items(): if param_key in self.DANGEROUS_PATTERNS: if isinstance(values, str): for pattern in self.DANGEROUS_PATTERNS[param_key]: if pattern.lower() in values.lower(): msg = f"Dangerous pattern '{pattern}' detected in param '{param_key}': {values}" logger.warning(msg) if self.safe_mode: return { 'allowed': False, 'reason': f"Security: {msg}", ...[truncated 3543 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Validate every macro event immediately before execution using the same centralized `SafetyInterlock` used by the main dispatcher. 2. Classify `play_macro` and `play_macro_with_subroutines` as risky actions requiring explicit user authorization. 3. Parse and validate the entire macro before launching playback: - Enforce an explicit action allowlist. - Validate required fields and parameter types. - Apply coordinate, duration, interval, timeout, and event-count limits. - Reject nested or unknown actions. 4. Propagate `dry_run` to the child process rather than removing it at the wrapper boundary. 5. Prefer in-process playback through a single guarded action manager instead of a separate script with duplicated execution logic. 6. Require confirmation for command-submission sequences, terminal activation, Enter presses, destructive shortcuts, and macros from untrusted locations. 7. Consider signing trusted macros or recording and verifying a content hash before execution. 8. Ensure sub-macro events receive identical validation and cannot bypass directory restrictions. ]]>
