Back to skill

Security audit

Anime Character Loader

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its stated purpose, but it can turn third-party character data into persistent agent behavior instructions, so it needs careful review before installation.

Install only if you are comfortable with the skill sending character and anime names to third-party anime/wiki services and generating agent persona files from that content. Review SOUL.generated.md carefully before choosing REPLACE or MERGE, especially any Background, Personality, Identity, or Boundaries text copied from remote sources.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Findings (1)

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. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (27)

YARA rule 'agent_skill_prompt_injection_hidden_instructions': Prompt injection or hidden instructions embedded in AI agent skill text [agent_skills]

High
Category
YARA Match
Content
+)\]\([^\)]+\)', r'\1', desc)
        
        # 清理多余换行
        desc = re.sub(r'\n{3,}', '\n\n', desc)
        
        # 防止 prompt injection: 移除角色标记和指令覆盖尝试
        # 移除常见的 injection 模式
        injection_patterns = [
            r'\[system\]:.*',           # [system]: ...
            r'\[user\]:.*',              # [user]: ...
            r'\[assistant\]:.*',         # [assistant]: ...
            r'ignore previous instructions.*',
            r'ignore all previous.*',
            r'reveal your.*prompt.*',
            r'system prompt.*',
            r'you are now.*',
            r'<system>.*</system>',
            r'<instruction>.*</instruction>',
        ]
        
        for pattern in injection_patterns:
            desc = re.sub(pattern, '', desc, flags=re.IGNORECASE)
        
        # 移除控制字符和零宽字符
        desc = re.sub(r'[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f-\x9f]', '', desc)
        desc = re.sub(r'[\u200b-\
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Instruction Override

High
Category
Prompt Injection
Content
r'\[system\]:.*',           # [system]: ...
            r'\[user\]:.*',              # [user]: ...
            r'\[assistant\]:.*',         # [assistant]: ...
            r'ignore previous instructions.*',
            r'ignore all previous.*',
            r'reveal your.*prompt.*',
            r'system prompt.*',
Confidence
80% confidence
Finding
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
Line L003 instructs users in Chinese to input a character name and generate the file, with no indication that other languages are supported for the skill description itself. This is a natural-language locale policy concern because the skill presents a mandatory-looking instruction in a specific language without user opt-in or an explicit language choice.

External Transmission

Medium
Category
Data Exfiltration
Content
weight: 0.5
    auth: none
  - name: Jikan (MyAnimeList)
    endpoint: https://api.jikan.moe/v4
    weight: 0.3
    auth: none
Confidence
92% confidence
Finding
The skill explicitly sends user-supplied character names and possibly anime titles to third-party services, expanding the trust boundary and creating an external data transmission/privacy risk. While the transmitted fields are low sensitivity in the documented use case, operators may still unintentionally disclose proprietary prompts, private project names, or sensitive query terms if they misuse the tool or adapt it for other inputs.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The file presents substantial usage, workflow, configuration, and error-handling guidance in Chinese, while other parts are in English, but it does not tell users that the skill is Chinese-only or offer an alternative language path. This can violate a language/locale policy when users are implicitly forced into a specific language without opt-in.

Intent-Code Divergence

Medium
Confidence
91% confidence
Finding
The file defines two competing identities: a generic helpful assistant and a specific anime character persona, without stating precedence or merge rules. This ambiguity can cause inconsistent behavior, weaken downstream safety or policy assumptions, and create prompt-confusion opportunities where the model follows the less constrained persona instead of the intended base identity.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code file contains natural-language documentation entirely in Chinese and also hard-codes a Chinese-language site domain later in the implementation, but it does not indicate that the skill is intentionally region- or locale-specific. Under the policy, forcing a specific language or locale without user opt-in or explicit justification is a natural-language policy concern.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code embeds user-facing descriptions and notes in Chinese, including the main module description and later result notes, without offering any language or locale choice. The policy requires avoiding forced language constraints unless the skill explicitly provides opt-in or clearly documents a justified region-specific limitation.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The `_generate_note` method returns user-facing status and warning text only in Chinese, including the warning about excerpted content. This imposes a specific language on all users without an opt-in mechanism or documented locale limitation.

External Transmission

Medium
Category
Data Exfiltration
Content
},
    "jikan": {
        "name": "Jikan (MyAnimeList)",
        "endpoint": "https://api.jikan.moe/v4",
        "weight": 0.3,
        "enabled": True,
    },
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
},
    "jikan": {
        "name": "Jikan (MyAnimeList)",
        "endpoint": "https://api.jikan.moe/v4",
        "weight": 0.3,
        "enabled": True,
    },
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The file is entirely written in Chinese and its name indicates a Chinese-specific README, but there is no note that this is an optional locale variant or that users can choose another language. Under the stated policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale constraint is explicitly documented and justified.

Scope Creep

Low
Category
Excessive Agency
Content
### Copyright Holders

Characters referenced in this tool belong to their respective creators and publishers including but not limited to:
- Saekano: © Fumiaki Maruto, Kurehito Misaki, KADOKAWA
- Rascal Does Not Dream: © Hajime Kamoshida, Keiji Mizoguchi, KADOKAWA
- And other respective copyright holders
Confidence
70% confidence
Finding
Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Natural-Language Policy Violations

Low
Confidence
86% confidence
Finding
This JSON includes quote entries and metadata in multiple languages/scripts, including Chinese and Japanese, while other entries use romanized Japanese and English. Because the file hard-codes locale-specific content without any natural-language indication of user opt-in or a documented region-specific purpose, it may violate the language/locale policy criterion.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
This markdown file uses Chinese throughout headings, instructions, and examples, which can amount to forcing a specific language on users without an explicit choice. The policy for natural-language violations applies to all file types and specifically covers language or locale constraints lacking user opt-in.

Intent-Code Divergence

Low
Confidence
90% confidence
Finding
The note says the file includes '原始台词: 1条 | 角色描述: 5条' and warns that character-description excerpts are included, while the top-level data structure is still presented as a quotes collection. This is a mild intent/documentation divergence because the file’s effective contents are mostly descriptive excerpts, not quotes spoken by the character.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
This JSON file contains user-facing note text in Chinese, including the warning label and descriptive content, while the rest of the file is largely in English. Because the file does not indicate that it is intended for a Chinese-only audience or provide an opt-in language choice, it may violate a language/locale policy requiring neutral or user-selectable language.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
beautifulsoup4>=4.12.0
Confidence
98% confidence
Finding
The dependency is specified with a lower bound only, which allows future installs to resolve to different versions over time. This weakens reproducibility and supply-chain control, and can unintentionally introduce vulnerable or breaking releases into the environment.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
91% confidence
Finding
The manifest references requests without pinning to a specific vetted version, and known advisories exist for some requests releases. Because the resolved installed version is unknown, there is a real risk that an affected version could be installed, especially in fresh or future environments.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
beautifulsoup4>=4.12.0
Confidence
98% confidence
Finding
The package is not pinned to a specific version, so builds are not deterministic and may pull different releases in different environments or at different times. This increases supply-chain risk and makes it harder to verify that only vetted dependency versions are installed.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The file-level docstring presents the skill entirely in Chinese, framing the tool's purpose and operating model in a single enforced language. Under the policy, locale or language constraints should either be optional for the user or clearly justified as region-specific; neither is indicated here.

Intent-Code Divergence

Low
Confidence
92% confidence
Finding
The docstring says Phase 2 is optimized for Fandom Quotes subpages with URLs like `/wiki/Character/Quotes`, but `fetch()` passes `_build_api_url(..., "page")`, which returns the main `/wiki/{character}` page. `_fetch_browser()` then appends `/Quotes`, producing `/wiki/{character}/Quotes` rather than a dedicated Quotes-page URL pattern, so the documented intent and implemented navigation strategy do not fully match.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The command-line success and failure messages shown to users are emitted only in Chinese. This creates a language policy issue because the skill does not provide a language choice or explain that it is restricted to Chinese-speaking users.

Intent-Code Divergence

Low
Confidence
97% confidence
Finding
The class docstring at L0347 describes this component as a usable 'Fandom Wikia' backup source. However, the only search method immediately returns None after a comment saying the source is skipped, so the documented intent contradicts the actual behavior.

Missing User Warnings

Low
Confidence
91% confidence
Finding
The write_text function creates parent directories and writes content to an arbitrary path, which is a safety-relevant file modification operation. There is no confirmation prompt, logging, print statement, or explanatory comment/docstring in the function indicating that it will create directories and overwrite file contents.

Static analysis

No suspicious patterns detected.