Back to skill

Security audit

Improvement Evaluator

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent evaluation purpose, but it can forward local file contents and untrusted skill text to an external Claude CLI without enough path or sandbox controls.

Install only if you intend to run skill evaluations that may call the Claude CLI. Use mock mode for local testing, run real evaluations in a sandbox or disposable workspace, and do not feed untrusted ranking artifacts or task suites unless target paths are reviewed and constrained to real SKILL.md files.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/evaluate.py:185
Finding

Unrestricted Local File Content Can Be Forwarded to an External LLM

Content
View full analysis
str: """Extract the SKILL.md content for a candidate. Candidates may have their own 'skill_content' or 'content' field. If not, read the original SKILL.md from the target path. """ # Check candidate for inline content for key in ("skill_content", "content", "body"): if key in candidate and candidate[key]: return candidate[key] # Fallback: read original SKILL.md from target target_path = Path(target.get("path", "")) skill_md = target_path / "SKILL.md" if target_path.is_dir() else target_path if skill_md.exists(): return skill_md.read_text(encoding="utf-8") raise ValueError(f"Cannot find SKILL.md content for candidate or at {target_path}") def get_baseline_skill_content(target: dict) -> str: """Read the original (baseline) SKILL.md from the target path.""" target_path = Path(target.get("path", "")) skill_md = target_path / "SKILL.md" if target_path.is_dir() else target_path if skill_md.exists(): return skill_md.read_text(encoding="utf-8") raise ValueError(f"Baseline SKILL.md not found at {target_path}") ``` The resulting content is passed into task execution: ```python candidate_skill = get_skill_content(candidate, target) logger.info("Running %d tasks for candidate '%s'...", len(tasks), args.candidate_id) candidate_results = run_task_suite(runner, candidate_skill, tasks, pass_k=args.pass_k) ``` ```python try: baseline_skill = get_baseline_skill_content(target) except ValueError: logger.warning("Baseline SKILL.md not found; using 0.0 as baseline") baseline_skill = None ``` `TaskRunner` then embeds t ...[truncated 3282 chars]
Remediation
View remediation

T01 · Skill Instruction Hijacking

Warning
Location
scripts/task_runner.py:99
Finding

Untrusted Skill and Task Instructions Are Executed in a Non-Isolated Claude CLI Context

Content
View full analysis
str: """Prepend SKILL.md content to the task prompt.""" return ( f"You have been given the following skill documentation to guide your work:\n\n" f"---BEGIN SKILL.MD---\n{skill_content}\n---END SKILL.MD---\n\n" f"Task: {task['prompt']}" ) ``` The prompt is passed to the Claude CLI without explicit tool restrictions, a controlled working directory, or a minimal environment: ```python def _execute_claude(self, prompt: str, timeout: int) -> str: """Call claude -p subprocess and return the text output.""" tmpdir = None try: tmpdir = tempfile.mkdtemp(prefix="evaluator_task_") prompt_file = Path(tmpdir) / "prompt.txt" prompt_file.write_text(prompt, encoding="utf-8") result = subprocess.run( ["claude", "-p", "--output-format", "json"], input=prompt, capture_output=True, text=True, timeout=timeout, ) ``` The LLM rubric judge creates a second unisolated model boundary containing attacker-influenced generated output: ```python prompt = ( f"You are a judge evaluating AI output quality.\n\n" f"## Rubric\n{rubric}\n\n" f"## AI Output\n{output[:3000]}\n\n" f"Score the output from 0.0 to 1.0 based on the rubric.\n" f"Respond with ONLY a JSON object: {{\"score\": , \"reasoning\": \"\"}}" ) try: result = subprocess.run( ["claude", "-p", "--output-format", "json"], input=prompt, capture_output=True, text=True, timeou ...[truncated 3112 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (24)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · tests/test_judges.py (reported line 110)May include surrounding context.

python
judge = PytestJudge()
        result = judge.evaluate(
            "some output",
            {"judge": {"test_file": "../../../etc/passwd"}},
        )
        assert result["passed"] is False
        assert "SECURITY" in result["details"]

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill describes operational behaviors that imply file access and shell execution (python3 scripts/evaluate.py, reading task suites, writing output artifacts and state) but does not declare any permissions or allowed-tools scope. That creates an under-specified trust boundary: a host agent may grant broader tool access than necessary, increasing the risk of unintended file modification, arbitrary command execution, or misuse of local state during evaluation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The manifest description and two trigger phrases are written in Chinese, while the rest of the document is in English, and there is no statement that the skill supports multiple languages or that Chinese is optional. This creates a locale/language policy concern because the skill implicitly constrains activation and description language without user opt-in or documented justification.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
91% confidence
Finding

This code executes pytest on a file path derived from task configuration, which means the skill can run arbitrary Python test code located under tests/fixtures. Although there are path-traversal checks, the design still grants code-execution capability to fixture authors and inherits the current process environment, so a malicious or compromised fixture can read secrets, access the network, or execute system commands.

Content

Scanner excerpt · interfaces/judges.py (reported line 85)May include surrounding context.

python
output_file = Path(tmpdir) / "ai_output.txt"
            output_file.write_text(output, encoding="utf-8")

            result = subprocess.run(
                ["python3", "-m", "pytest", str(test_path), "-v",
                 "--tb=short", f"--rootdir={tmpdir}"],
                capture_output=True,

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · interfaces/judges.py (reported line 92)May include surrounding context.

python
text=True,
                timeout=60,
                env={
                    **__import__("os").environ,
                    "AI_OUTPUT_FILE": str(output_file),
                },
            )

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill metadata emphasizes predefined task-suite evaluation and pass/fail measurement, but this judge adds a separate model-calling capability that can transmit evaluated content outside the local process. In this context, that broader capability is unnecessary for many evaluation tasks and increases the attack surface, especially because skill outputs may contain sensitive prompts, data, or proprietary content.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

AI output is sent to an external CLI for scoring without any visible disclosure, consent, or sensitivity checks. If the evaluated output contains secrets, internal prompts, customer data, or proprietary code, this creates a quiet exfiltration path and a compliance/privacy risk even when the command itself is not attacker-controlled.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
88% confidence
Finding

The skill invokes an external 'claude' CLI and sends model output plus rubric data to it. This creates an external data-flow and command-execution boundary: sensitive output may be exfiltrated to a third-party service, and the evaluation pipeline now depends on a locally installed external binary whose behavior and trust boundary are outside the skill itself.

Content

Scanner excerpt · interfaces/judges.py (reported line 151)May include surrounding context.

python
f"Respond with ONLY a JSON object: {{\"score\": <float>, \"reasoning\": \"<str>\"}}"
        )
        try:
            result = subprocess.run(
                ["claude", "-p", "--output-format", "json"],
                input=prompt,
                capture_output=True,

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill is described as validating improvements via a predefined task suite, but the implementation actually forwards skill documentation and prompts to an external Claude CLI. That mismatch creates a confused-deputy risk: evaluating potentially adversarial skill content by handing it to another powerful agent can cause side effects or data exposure inconsistent with a local deterministic evaluator.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
88% confidence
Finding

This code spawns an external claude subprocess and sends it prompt content derived from skill_content and task data. Even though the command arguments are fixed and there is no shell injection, invoking an external model/CLI materially expands the trust boundary: untrusted skill content is executed in effect by a powerful external agent, which may perform unintended actions depending on CLI capabilities and environment configuration.

Content

Scanner excerpt · scripts/task_runner.py (reported line 115)May include surrounding context.

python
prompt_file = Path(tmpdir) / "prompt.txt"
            prompt_file.write_text(prompt, encoding="utf-8")

            result = subprocess.run(
                ["claude", "-p", "--output-format", "json"],
                input=prompt,
                capture_output=True,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The evaluator's core function depends on spawning an unrestricted external subprocess without evidence of sandboxing or capability minimization. Because the subprocess consumes untrusted skill_content, the skill context makes this more dangerous: the evaluator is specifically designed to process adversarial or candidate skill text, so prompt-injection-style instructions can be relayed into a capable external agent during evaluation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This YAML task suite repeatedly instructs the model to generate output in Chinese, which is a natural-language locale constraint. The file does not offer a user choice of language or explain a documented region-specific requirement, so it matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The instruction 'Generate in Chinese' forces a locale choice in the task definition. Under the stated policy, locale constraints should either be optional for the user or clearly justified as region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The prompt explicitly requires output in Chinese markdown, enforcing a specific language for the skill behavior. Because the file provides no opt-in or justification for this locale restriction, it is a policy-relevant natural-language constraint.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The task suite explicitly rewards broad symptom keywords like "leak", "RSS", and "OOM" in triggers while only weakly enforcing boundaries through a partial-score rubric. This can train or validate a skill-creator to produce overbroad routing metadata, causing incorrect skill activation and prompt hijacking opportunities where unrelated user requests match vague symptoms.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · task_suites/skill-creator/task_suite.yaml (reported line 143)May include surrounding context.

yaml
- id: "sc-init-script"
    description: "Must reference the init_skill.py script for initializing new skills"
    prompt: |
      I want to create a new skill called "log-analyzer" at ~/.claude/skills/log-analyzer.
      What is the correct way to initialize the skill directory structure?
      Show the command and explain what it creates.
    judge:

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · task_suites/skill-distill/task_suite.yaml (reported line 123)May include surrounding context.

yaml
1. Must show a distillation plan (target skill name, body content summary, references list, conflicts, dropped items). Score 0.0 if it skips straight to generating files.
        2. Must explicitly ask for user confirmation before proceeding to Phase 4. Score 0.0 if it auto-generates.
        3. Should mention source skill handling options (preserve/replace/downgrade). Score 0.5 if plan shown but source handling missing.
        Score 1.0 if full plan + explicit confirmation request. Score 0.0 if it generates files without confirmation.
      pass_threshold: 0.7
    timeout_seconds: 120

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
80% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

Scanner excerpt · task_suites/skill-distill/task_suite.yaml (reported line 131)May include surrounding context.

yaml
- id: "sd-pipeline-verification"
    description: "Must require improvement-learner scoring after generation (Phase 4 verification)"
    prompt: |
      I've confirmed the distillation plan. You generated the new skill at ~/.claude/skills/web-toolkit/SKILL.md with 3 references files.

      What verification steps must happen next? List the exact commands.
    judge:

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This YAML task suite repeatedly requires prompts, outputs, and evaluation criteria in Chinese, including Chinese-only user inputs and rubric expectations. Because the file does not offer a language choice or explain a justified region-specific constraint, it constitutes a natural-language locale policy violation under the stated rules.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

This markdown file contains user-facing natural language in multiple languages, with lines L08-L09 switching to Chinese while the rest of the document is in English. Under the language/locale policy rule, forcing or mixing languages without user opt-in or clear justification can create a policy inconsistency for users expecting a single documented locale.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

This JSON fixture contains multiple natural-language commit messages written in Chinese, while the file provides no indication that the skill is region-specific or that non-Chinese output is optional. Under the stated policy, forcing or assuming a specific language without user opt-in can be a locale-policy violation.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

This manifest describes the skill in very broad terms as evaluating and removing AI patterns from text, but it does not define any explicit invocation phrases, scope limits, or exclusion conditions. In a manifest file, such open-ended wording can contribute to unintended activation because many ordinary rewriting requests could match the description.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The file mixes English and Chinese task content, including a fully Chinese prompt, but does not explain whether multilingual behavior is optional, user-selected, or required for a specific region or audience. This can conflict with language/locale policy expectations when a skill implicitly operates in a specific language without documented opt-in or justification.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This YAML manifest describes the skill's capabilities in broad terms but does not specify any concrete activation phrases, contextual limits, or exclusion conditions. For manifest files, missing specificity around when the skill should activate can lead to unintended invocation by overlapping with general requests about analysis, classification, or token budgets.

Content

No source excerpt is available for this finding.