T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/red-team.py:109
- Finding
- Untrusted Prompt Content Is Passed to Tool-Capable Coding Agents Without Isolation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/red-team.py:109-127, 135-145, 185-250, 298-307, 334-340` **Vulnerability Type**: Prompt injection through untrusted context, custom personas, and model-generated debate content **Risk Level**: High ### Complete Vulnerable Code Snippets ```python def _build_cmd(backend: str, system: str, user_msg: str, model: str) -> tuple[list[str], str | None]: """Build the CLI command and optional stdin for the given backend.""" combined_prompt = f"{system}\n\n---\n\n{user_msg}" if backend == "claude": return [ "claude", "--print", "--model", model, "--output-format", "text", "--no-session-persistence", "--append-system-prompt", system, user_msg, ], None elif backend == "codex": # Codex exec reads prompt from positional arg or stdin return [ "codex", "exec", "--model", model, "--quiet", combined_prompt, ], None elif backend == "gemini": # Gemini CLI: prompt as positional arg return [ "gemini", "-p", combined_prompt, ], None ``` ```python def call_agent(system: str, user_msg: str, label: str, model: str = "sonnet", backend: str = "claude") -> str: """Call a coding agent CLI with a system prompt and user message.""" print(f" ⏳ {label}...", end=" ", flush=True) t0 = time.time() cmd, stdin_data = _build_cmd(backend, system, user_msg, model) try: result = subprocess.run( cmd, capture_output=True, text=True, input=stdin_data, timeout=180, ) ``` ```python def run_debate(question: str, persona_keys: list[str], personas: dict, rounds: int, context: str, model: str, backend: str = "claude") -> str: ctx_block = f"\n\n## Additional Context\n{context}" if context else "" # . ...[truncated 5186 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Use a text-only inference interface** - Prefer an API or CLI mode that cannot execute tools, shell commands, filesystem operations, or network requests. - Explicitly disable all agent tools rather than relying on default backend behavior. 2. **Run every backend in a constrained sandbox** - Use a dedicated empty working directory. - Mount required inputs as read-only. - Deny access to the user's home directory, project files, SSH configuration, cloud credentials, and other secrets. - Disable network access unless it is strictly required. - Run under a low-privilege account with a minimal environment. - Remove credential-bearing environment variables before starting the subprocess. 3. **Establish clear prompt trust boundaries** - Mark the question, context file, prior model output, and persona metadata as untrusted quoted data. - Add a fixed trusted instruction stating that content inside data blocks must never be treated as operational instructions. - Do not allow arbitrary custom persona text to replace or extend trusted system instructions without explicit review. 4. **Validate custom personas** - Apply length and schema limits. - Reject or require confirmation for persona definitions containing tool-use requests, command instructions, requests to access files, or attempts to override higher-priority instructions. - Keep persona worldview text in a user-level data section instead of passing it directly as a system prompt. 5. **Prevent cross-round instruction propagation** - Treat every agent response as untrusted before including it in later prompts. - Use structured outputs and extract only expected analytical fields. - Apply output size limits and detection for instruction-like payloads before reuse. 6. **Require approval for exceptional capabilities** - If tool access is intentionally supported, display the exact requested capability and obtain explicit user app ...[truncated 408 chars]
