T09 · Insecure Skill Coding Practices
Warning
- Location
- business_mind_tree.py:99
- Finding
- Unredacted Sensitive Business Data Is Transmitted to an External AI Provider<![CDATA[ ## Vulnerability Details **File Location**: `business_mind_tree.py`, lines 99–125 and 603–611 **Vulnerability Type**: External transmission of potentially sensitive input without data minimization **Risk Level**: Medium ### Complete Code Snippet ```python def _call_openrouter_primary(model: str, system: str, user: str, max_tokens: int) -> tuple: """Primary council backend. Uses OPENROUTER_API_KEY.""" try: from openai import OpenAI except ImportError: raise RuntimeError( "openai package not installed. " "Run: pip install openai --break-system-packages" ) api_key = os.environ.get("OPENROUTER_API_KEY") if not api_key: raise RuntimeError("OPENROUTER_API_KEY not set in environment") or_model = _to_or_model(model) client = OpenAI(api_key=api_key, base_url="https://openrouter.ai/api/v1") resp = client.chat.completions.create( model=or_model, max_tokens=max_tokens, messages=[ {"role": "system", "content": system}, {"role": "user", "content": user}, ], extra_headers={ "HTTP-Referer": os.environ.get("OPENROUTER_APP_URL", "https://github.com/openclaw"), "X-Title": os.environ.get("OPENROUTER_APP_NAME", "Multi-Council Decision Engine"), }, ) ``` The transmitted user value is assembled without filtering: ```python def _run_council(name: str, prompt: str, context: str = "") -> dict: """Generic council runner. Returns structured analysis dict.""" if name not in COUNCILS: return {"council": name, "ok": False, "error": f"unknown council: {name}"} cfg = COUNCILS[name] user = prompt.strip() if context.strip(): user += f"\n\nAdditional context:\n{context.strip()}" ``` ### Technical Analysis The Skill sends the complete caller-supplied prompt and optional context to OpenRouter over its chat-completions API. Gate functions can place venture pro ...[truncated 2726 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Add a documented data-handling boundary stating that prompts are transmitted to OpenRouter and may be routed to downstream model providers. 2. Require explicit caller confirmation before processing inputs classified as confidential, personal, regulated, or customer-provided. 3. Add a configurable preprocessing layer that detects or redacts: - API keys and bearer tokens - Passwords and private keys - Email addresses, phone numbers, and government identifiers - Payment and financial-account data - Other application-specific sensitive fields 4. Prefer structured inputs with allowlisted fields instead of accepting unrestricted serialized objects. 5. Add a `sensitive_data_policy` or equivalent callback so integrating applications can reject prohibited input before any network request. 6. Offer an approved local or private model backend for sensitive decisions. 7. Clearly expose the selected model and provider before submission, particularly when dynamic model selection can route content to different vendors. 8. Avoid sending identical sensitive material to every council where a minimized or purpose-specific subset would suffice. 9. Add automated tests confirming that known secret and PII patterns are rejected or redacted before `_call_openrouter_primary()` is reached. ]]>
