T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/run-duo.py:75
- Finding
- Unfiltered Sandbox Contents Are Transmitted to an External API<![CDATA[ ## Vulnerability Details **File Location**: `scripts/run-duo.py:52-68, 75-90`; equivalent behavior in `scripts/run-trio.py:60-76, 83-97`; risky usage guidance in `SKILL.md:116-123` **Vulnerability Type**: Uncontrolled transmission of local workspace data to an external service **Risk Level**: Medium ### Complete Code Snippet ```python def call_gemini(system_prompt: str, user_prompt: str) -> str: """Call Gemini API with the given prompts.""" url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-preview:generateContent?key={API_KEY}" payload = { "contents": [ { "role": "user", "parts": [{"text": f"{system_prompt}\n\n---\n\n{user_prompt}"}] } ], "generationConfig": { "temperature": 0.9, "maxOutputTokens": 2048 } } response = requests.post(url, json=payload) if response.status_code == 200: data = response.json() return data["candidates"][0]["content"]["parts"][0]["text"] else: return f"ERROR: {response.status_code} - {response.text}" def read_sandbox() -> str: """Read all sandbox files into a string.""" contents = [] for file in SANDBOX.rglob("*"): if file.is_file() and file.name != "run-experiment.py" and file.name != "experiment-log.md": try: contents.append(f"\n### {file.relative_to(SANDBOX)}\n```\n{file.read_text()}\n```") except: pass return "\n".join(contents) ``` The collected content is then placed in the API prompt: ```python workspace = read_sandbox() user_prompt = f"Here is the workspace you need to analyze:\n{workspace}\n\nProvide your analysis and recommendations." ``` The documentation also encourages potentially sensitive test data: ```markdown ### Modify the Sandbox Create custom scenarios in `/tmp/chaos-sandbox/`: - Add realistic project files - Include edge c ...[truncated 2756 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace recursive collection with an explicit, user-approved allowlist of files. 2. Display the exact files and total byte count before transmission, then require confirmation. 3. Exclude sensitive patterns by default, including: - `.env` - Private keys and certificate key files - Cloud credential files - Token and password stores - Files named `credentials`, `secrets`, or similar 4. Add secret scanning and redact likely credentials before constructing the prompt. 5. Enforce strict per-file and aggregate size limits. 6. Resolve every candidate path and verify that it remains beneath the resolved sandbox root. 7. Reject symlinks and non-regular files unless explicitly approved. 8. Use synthetic fixtures rather than genuine sensitive configurations for experiments. 9. Clearly disclose that selected content is sent to Google Gemini and may be subject to external processing policies. 10. Where supported by the provider, move the API key from the query string to an authentication header. 11. Add connection and read timeouts, request-size controls, and explicit exception handling. 12. Avoid returning the provider’s complete error body where it could expose request or account details. ]]>
