T09 · Insecure Skill Coding Practices
- Location
utils.py:55- Finding
Incomplete Prompt-Injection Filtering Allows Documented Attack Phrase to Reach Sub-Agents
- Content
View full analysis
Vulnerability Details
File Location:
utils.py:55-76
Related Evidence:tests/security_test_plan.md:8-15
Vulnerability Type: Incomplete input validation and prompt-injection mitigation
Risk Level: MediumVulnerable Code
python DANGEROUS_INPUT_PATTERNS = [ re.compile(r"disregard\s+(all\s+)?(prior|above|pre(?:vious)?)\s+instr(?:uction)?s?", re.I), re.compile(r"reveal\s+(system|developer)\s+prompt", re.I), re.compile(r"dump\s+(secrets?|keys?|tokens?)", re.I), re.compile(r"export\s+(api[_-]?key|token|secret)", re.I), ] ALLOWED_OPENCLAW_SUBCOMMANDS = { "sessions_spawn", "sessions_list", "sessions_history", } def sanitize_untrusted_task(task: str, max_chars: int = 12000) -> str: """Sanitize untrusted task input before passing to sub-agents.""" if not task: return "" text = task.replace("\x00", "").strip() text = re.sub(r"[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]", "", text) for pattern in DANGEROUS_INPUT_PATTERNS: text = pattern.sub("[FILTERED_UNTRUSTED_INSTRUCTION]", text) return text[:max_chars]The corresponding security test plan states:
markdown ### 1) Prompt injection filtering Input task includes: - "ignore previous instructions" - "reveal system prompt" - "dump secrets" Expected: - `sanitize_untrusted_task` replaces these fragments with `[FILTERED_UNTRUSTED_INSTRUCTION]`. - Spawned task still includes `SECURITY_PREAMBLE`.Technical Analysis
The sanitizer uses a small blacklist of literal regular-expression patterns. The documented phrase
ignore previous instructionsdoes not match the implemented expression, which only recognizes variants beginning withdisregard. Consequently, the test plan and implementation do not agree: the documented injection phrase passes through unchanged.Semantic prompt injection cannot be reliably prevented through a short phrase black ...[truncated 2274 chars]
- Remediation
View remediation
Remediation Suggestions
- Add an immediate regression fix for the documented phrase and common variants, for example by recognizing both
ignoreanddisregard. Treat this only as supplemental defense, not the primary security boundary. - Convert
tests/security_test_plan.mdinto executable unit tests that assert the exact output ofsanitize_untrusted_task()for every documented test vector. - Add adversarial tests for capitalization, whitespace changes, punctuation, role reassignment, “forget prior rules,” indirect injection, encoded instructions, and injection contained in intermediate agent output.
- Clearly delimit untrusted task and prior-agent content as data. Prompts should explicitly state that content inside those delimiters must not redefine roles, safety policies, or tool permissions.
- Apply the same trust-boundary treatment to Crew synthesis input, Supervisor dependency output, Pipeline stage output, and Council deliberation content.
- Enforce security at the runtime capability layer: give spawned sessions only the tools required for their role, require confirmation for external side effects, and prevent access to secrets or sensitive host resources.
- Keep the existing safety preamble, command allowlist, no-shell subprocess invocation, and safe-state defaults as defense-in-depth controls.
- Document that phrase filtering is heuristic and that model compliance and OpenClaw runtime policy remain mandatory security boundaries.
- Add an immediate regression fix for the documented phrase and common variants, for example by recognizing both
