T01 · Skill Instruction Hijacking
Warning
- Location
- src/anime_character_loader/legacy.py:506
- Finding
- Untrusted API Content Can Become Persistent Agent Instructions<![CDATA[ ## Vulnerability Details **File Location**: `src/anime_character_loader/legacy.py:506-623` **Vulnerability Type**: Incomplete prompt-injection neutralization in generated agent instructions **Risk Level**: Medium ### Vulnerable Code ```python def generate_soul(self, match: CharacterMatch) -> str: """生成 SOUL.md""" data = match.data name = self._sanitize_field(data.get("name", "Unknown")) source_work = self._sanitize_field(match.source_work) # 清洗描述 description = self._clean_description(data.get("description", "")) # 提取性格特征 traits = self._extract_personality(description) # 构建 SOUL lines = [ f"# {name}", "", f"**Source:** {source_work}", "", ] if data.get("name_native"): native_name = self._sanitize_field(data['name_native']) lines.append(f"**Japanese Name:** {native_name}") if data.get("aliases"): safe_aliases = [self._sanitize_field(a) for a in data['aliases'][:3]] lines.append(f"**Also Known As:** {', '.join(safe_aliases)}") lines.extend([ "", "---", "", "## Identity", "", f"You are {name}, a character from {match.source_work}.", "", ]) if description: lines.extend([ "## Background", "", description[:800] if len(description) > 800 else description, "", ]) lines.extend([ "## Personality", "", ]) if traits: for trait in traits[:5]: lines.append(f"- {trait}") ``` ```python def _clean_description(self, desc: str) -> str: """清洗描述文本 - 防止 prompt injection""" if not desc: return "" # 移除 HTML 标签 desc = re.sub(r'<[^>]+>', '', desc) # 移除 markdown 链接 desc = re.sub(r'\[([^\]]+)\]\([^\)]+\)', r'\1', desc) # 清理多余换行 desc = re.sub(r'\n{3,}', '\n\n', desc) # 防止 prompt injection: 移除角色标记和指令覆盖尝试 # 移除常见的 injection 模式 ...[truncated 3635 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Separate data from instructions** - Treat remote descriptions, aliases, and work titles solely as quoted reference data. - Do not place remote prose directly into sections interpreted as agent instructions. - Store source material in a clearly delimited metadata or reference section. 2. **Generate behavior only from trusted templates** - Construct Identity, Personality, Speaking Style, and Boundaries from local, reviewed templates. - If structured traits are needed, map validated values to a fixed allowlist of locally defined phrases. 3. **Sanitize every remote field consistently** - Replace `match.source_work` with the already sanitized `source_work` variable in the Identity section. - Apply strict length, character, Unicode-normalization, and formatting constraints to names, aliases, descriptions, and source-work fields. 4. **Avoid relying on phrase denylists** - Retain denylist checks only as defense in depth. - Flatten Markdown headings, block quotes, role labels, code blocks, XML-like tags, and other instruction-bearing syntax. - Reject content containing imperative or role-changing structures rather than attempting to remove a small set of phrases. 5. **Require explicit trust confirmation** - Clearly label generated content as remotely sourced and untrusted. - Require manual review before REPLACE or MERGE operations. - Present a diff showing exactly which remote text will enter `SOUL.md`. 6. **Add adversarial tests** - Test paraphrased directives, Unicode obfuscation, multiline role markers, Markdown-based injections, and instructions split across fields. - Verify that no upstream-controlled value can become an agent directive. ]]>
