Back to skill

Security audit

agent-eval-harness

Security checks for vulnerabilities and agentic risk

Overview

The skill includes a useful regression-test harness, but it also adds persistent self-learning memory that can write outside its own package and influence future behavior.

Review this before installing. Use it only if you are comfortable with local persistent memory files, avoid putting secrets or personal data in notes/preferences, and do not let stored learner output automatically modify skill instructions without reviewing the exact change.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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)

T02 · Agent Memory Poisoning

Warning
Location
scripts/learner.py:72
Finding

Persistent Agent Memory Poisoning Through Unvalidated Learning Data

Content
View full analysis

Vulnerability Details

File Location: scripts/learner.py:72-93; related behavioral instructions in SKILL.md:48-76
Vulnerability Type: Persistent storage of attacker-controlled preferences and operational notes
Risk Level: Medium

Vulnerable Code:

python
def record_op(skill_dir, capability, success=True, error=None, note=None):
    data = load_learning(skill_dir)
    data["totalOps"] += 1
    cap = data["capabilityStats"].setdefault(capability, {"count": 0, "success": 0, "fail": 0})
    cap["count"] += 1
    if success:
        cap["success"] += 1
    else:
        cap["fail"] += 1
        data["totalErrors"] += 1
    if error:
        ep = data["errorPatterns"].setdefault(error, {"count": 0, "lastNote": "", "lastTime": ""})
        ep["count"] += 1
        ep["lastNote"] = note or ""
        ep["lastTime"] = data["lastUpdated"] or datetime.datetime.now().strftime("%Y-%m-%dT%H:%M")
    rec = {"t": data["lastUpdated"], "cap": capability, "ok": success, "err": error, "note": note}
    data["recentOps"].append(rec)
    data["recentOps"] = data["recentOps"][-20:]
    save_learning(skill_dir, data)
    return data

def record_preference(skill_dir, key, value):
    data = load_learning(skill_dir)
    data["preferences"][key] = value
    save_learning(skill_dir, data)
    return data

The reflection mechanism subsequently includes stored error names and notes in recommendations:

python
def self_reflect(skill_dir):
    data = load_learning(skill_dir)
    suggestions = []
    for err, info in data["errorPatterns"].items():
        if info["count"] >= THRESHOLD_ERROR:
            suggestions.append(
                f"⚠️ 错误「{err}」已出现 {info['count']} 次,建议增加预检/兜底步骤,"
                f"并将经验回写本技能 SKILL.md(lastNote: {info.get('lastNote','')})"
            )

Technical Analysis

The prefer and record commands accept arbitrary preference keys, pre ...[truncated 2697 chars]

Remediation
View remediation

Remediation Suggestions

  1. Treat every value loaded from learned_patterns.json as untrusted data rather than an instruction.
  2. Do not automatically apply stored preferences to later sessions. Require explicit user confirmation before a preference affects agent behavior.
  3. Remove the workflow that recommends directly writing accumulated notes or error content into SKILL.md.
  4. If Skill updates are necessary, generate a structured change proposal and require a trusted reviewer to approve the exact diff.
  5. Define strict schemas and allowlists for preference keys, capability names, and error types.
  6. Apply length limits and reject control sequences, markup, prompt directives, and multiline instruction-like content in stored values.
  7. Keep telemetry, user preferences, and executable agent instructions in separate files with separate trust boundaries.
  8. Render stored values as quoted data with clear provenance rather than interpolating them into authoritative recommendations.
  9. Record the origin and trust level of each entry and ignore untrusted entries when constructing agent context.
  10. Add tests proving that stored notes and preferences cannot modify system prompts, Skill instructions, tool permissions, or safety constraints.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/learner.py:63
Finding

Plaintext Retention of Potentially Sensitive User-Provided Data

Content
View full analysis

Vulnerability Details

File Location: scripts/learner.py:63-93; data-retention behavior documented in SKILL.md:55-73
Vulnerability Type: Unrestricted plaintext storage of preferences, errors, and notes
Risk Level: Low

Vulnerable Code:

python
def save_learning(skill_dir, data):
    data["lastUpdated"] = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M")
    p = learn_path(skill_dir)
    with open(p, "w", encoding="utf-8") as f:
        f.write(json.dumps(data, indent=2, ensure_ascii=False))

def record_op(skill_dir, capability, success=True, error=None, note=None):
    data = load_learning(skill_dir)
    data["totalOps"] += 1
    cap = data["capabilityStats"].setdefault(capability, {"count": 0, "success": 0, "fail": 0})
    cap["count"] += 1
    if success:
        cap["success"] += 1
    else:
        cap["fail"] += 1
        data["totalErrors"] += 1
    if error:
        ep = data["errorPatterns"].setdefault(error, {"count": 0, "lastNote": "", "lastTime": ""})
        ep["count"] += 1
        ep["lastNote"] = note or ""
        ep["lastTime"] = data["lastUpdated"] or datetime.datetime.now().strftime("%Y-%m-%dT%H:%M")
    rec = {"t": data["lastUpdated"], "cap": capability, "ok": success, "err": error, "note": note}
    data["recentOps"].append(rec)
    data["recentOps"] = data["recentOps"][-20:]
    save_learning(skill_dir, data)
    return data

def record_preference(skill_dir, key, value):
    data = load_learning(skill_dir)
    data["preferences"][key] = value
    save_learning(skill_dir, data)
    return data

Technical Analysis

The learning module serializes its complete state to learned_patterns.json as ordinary UTF-8 JSON. User-provided preference keys and values, error descriptions, capability names, and notes are stored without sensitivity detection, redaction, encryption, retention limits, or a deletion interface.

Although recentOps is ...[truncated 1489 chars]

Remediation
View remediation

Remediation Suggestions

  1. Store mutable learning state in a private application-data directory rather than inside the Skill package.
  2. Create state files with restrictive permissions, such as owner read and write access only.
  3. Warn users not to provide credentials, tokens, personal information, or other secrets in notes and preference values.
  4. Add secret and personal-data detection before persistence, and redact recognized sensitive patterns.
  5. Minimize retained data by storing normalized error identifiers instead of complete free-form notes.
  6. Define expiration periods for preferences, error details, and operation history.
  7. Provide commands to inspect, selectively delete, and completely purge stored learning data.
  8. Avoid retaining command-line values that may also be exposed through shell history or process listings; support protected standard input where sensitive values are unavoidable.
  9. Document the storage location, retention policy, access model, and privacy implications.
  10. If sensitive persistence is a legitimate requirement, use an operating-system credential store or encryption with keys maintained separately from the data file.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The manifest presents the skill as a regression-evaluation harness, but the documentation also introduces a generic self-learning and user-memory subsystem unrelated to that narrow purpose. This mismatch is dangerous because users and orchestrators may authorize the skill for benchmarking, while it also accumulates preferences, errors, and usage history that materially expand privacy and persistence risk.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The module is explicitly designed as a generic self-evolution component for any skill and accepts arbitrary skill directories, including paths outside the current package and under ~/.workbuddy/skills. In a regression evaluation harness, this creates an unnecessary cross-skill write capability that can alter other skills' state and behavior, expanding the trust boundary well beyond evaluation-only functionality.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding

The skill documentation describes file-writing behavior via persistent memory files (learned_patterns.json, regression.jsonl) but does not declare any tool scope, permissions, or allowed-tools boundaries. This creates an undeclared capability gap: operators may treat the skill as lower risk than it is, while it can persist data locally and modify state across runs.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The added self-learning/user-memory subsystem extends the skill from evaluation into persistent profiling and adaptation. That is a substantive scope expansion, and in security terms it increases attack surface and data handling obligations without being justified by the stated regression-testing context.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Persisting user preferences and usage memory is not necessary for a regression-evaluation harness and introduces avoidable data retention. Even if intended as convenience, storing capability usage, error details, and preferences can expose sensitive operational or personal information over time.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill instructs users to save learned data, failure reasons, notes, and preferences into a local JSON file without any privacy warning, retention limit, or handling guidance. This can lead to accidental storage of sensitive user data or internal operational details in plaintext, where it may later be exposed or misused.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The instructions encourage storing user preferences, repeated errors, and usage details in a local memory file, creating a natural-language data leak and retention risk. Such free-form records often capture sensitive context that is hard to classify, redact, or safely retain, especially when no minimization or expiration policy exists.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The example command stores 输出语言 --val 中文 as the preference to be used directly on subsequent invocations, and the surrounding document is entirely framed in Chinese without offering an opt-in language choice. Under the language/locale policy, skills should not impose a specific language unless the constraint is justified or users are explicitly offered a choice.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The file implements a reusable self-improvement framework rather than evaluation-specific logic, including stateful learning, preference storage, and reflective suggestions for any skill. In the context of an eval harness, this unauthorized capability broadens persistence and behavioral modification beyond what users and reviewers would expect.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Natural-language strings in the top-level description are exclusively Chinese, and the command output/help text throughout the file follows the same pattern. This creates a language policy issue because the skill forces one language without opt-in or explanation that it is intended for a Chinese-only environment.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code records user preferences for arbitrary skills even though the declared skill purpose is regression evaluation. This introduces unnecessary collection and persistence of potentially sensitive user-specific data, creating privacy and scope-creep risk without a clear operational need.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The script writes operation history, error notes, and user preferences to disk without any nearby privacy notice, consent flow, or retention controls. Because notes and preferences can contain sensitive or identifying information, silent persistence increases the risk of unintended disclosure or overcollection.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

This Python file contains natural-language docstring usage instructions entirely in Chinese, and later prints Chinese-only usage/output text. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation, and no opt-in or region-specific justification is provided here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script prints status and usage messages only in Chinese during execution. Because the file does not offer a language selection mechanism or explain a justified locale restriction, this conflicts with the language/locale policy requirement.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.