Back to skill

Security audit

Vocabulary Anti Forgetting

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent vocabulary review tool, but a path bug can write or overwrite a progress log in the launch directory instead of the documented workspace memory folder.

Review this before installing or running. The skill does not show signs of exfiltration or hidden malicious behavior, but set REVIEW_MEMORY_DIR to a trusted memory folder before use and avoid running it from a directory that already contains an unrelated review_log.md.

Vulnerability Patterns
  • 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
  • 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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
review.py:20
Finding

Incorrect Default Path Resolution Can Overwrite an Unrelated Review Log

Content
View full analysis

Vulnerability Details

File Location: review.py, lines 20–22, with the resulting write at lines 237–254
Vulnerability Type: Incorrect path fallback and unintended file overwrite
Risk Level: Medium

Vulnerable Code

python
SKILL_DIR = Path(__file__).parent
WORKSPACE_DIR = SKILL_DIR.parent.parent  # .../skills/vocabulary-anti-forgetting/ -> .../workspace-root/
MEMORY_DIR = Path(os.environ.get("REVIEW_MEMORY_DIR", "")) or WORKSPACE_DIR / "memory"
LOG_PATH = MEMORY_DIR / "review_log.md"

The resolved path is later created and written without validating that it is the intended memory directory:

python
def ensure_log_exists():
    MEMORY_DIR.mkdir(parents=True, exist_ok=True)
    if not LOG_PATH.exists():
        LOG_PATH.write_text(INITIAL_LOG, encoding="utf-8")
python
def write_review_log(log: ReviewLog):
    lines = [
        "# Vocabulary Review Log\n",
        "\n",
        f"> **Total sessions:** {log.total_sessions}\n",
        f"> **Last session date:** {log.last_session_date}\n",
        "\n",
        "| id | vocabulary | level | review_count | last_reviewed | next_review_date |\n",
        "|---|---|---|---|---|---|\n",
    ]
    for entry in sorted(log.entries.values(), key=lambda e: e.id):
        last = entry.last_reviewed.isoformat() if entry.last_reviewed else "—"
        nxt = entry.next_review_date.isoformat() if entry.next_review_date else "—"
        lines.append(
            f"| {entry.id} | {entry.vocabulary} | {entry.level} "
            f"| {entry.review_count} | {last} | {nxt} |\n"
        )
    LOG_PATH.write_text("".join(lines), encoding="utf-8")

Technical Analysis

The expression intended to select a default memory directory is incorrect:

python
Path(os.environ.get("REVIEW_MEMORY_DIR", "")) or WORKSPACE_DIR / "memory"

When REVIEW_MEMORY_DIR is absent, os.environ.get() returns an empty string. Howe ...[truncated 2186 chars]

Remediation
View remediation

Remediation Suggestions

Test the environment-variable string before constructing a Path:

python
memory_dir_value = os.environ.get("REVIEW_MEMORY_DIR")
MEMORY_DIR = (
    Path(memory_dir_value).expanduser()
    if memory_dir_value
    else WORKSPACE_DIR / "memory"
)
LOG_PATH = MEMORY_DIR / "review_log.md"

Apply the following additional hardening measures:

  1. Resolve and validate the selected directory with Path.resolve() before writing.
  2. Confirm that the default path remains beneath the expected workspace root.
  3. If an override is supported, document that it must refer to a trusted directory and reject paths that resolve to a regular file.
  4. Validate any pre-existing log before replacing it; refuse to overwrite malformed or unrelated content unless the user explicitly confirms.
  5. Write updates atomically by creating a temporary file in the same directory, flushing it, and replacing the destination with os.replace().
  6. Preserve a backup before replacing an existing log where recovery is important.
  7. Add regression tests verifying that an unset or empty REVIEW_MEMORY_DIR resolves to <workspace>/memory, while a non-empty override resolves to the explicitly supplied directory.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (8)

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · asset/vocabulary_bank.md (reported line 1544)May include surrounding context.

md
| 1538 | comical | 滑稽的;好笑的;可笑的 |
| 1539 | nullify | 使无效;废除;取消 |
| 1540 | valor | 英勇;勇气;英雄气概 |
| 1541 | whether or not pardon erase history | 赦免是否能抹去历史 |
| 1542 | DC US Attorney's Office | 美国华盛顿特区联邦检察官办公室 |
| 1543 | memo | 备忘录;便条;内部通知 |
| 1544 | blue | 蓝色;忧郁的;(政治)民主党的;黄色的(英式) |

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · asset/vocabulary_bank.md (reported line 1548)May include surrounding context.

md
| 1538 | comical | 滑稽的;好笑的;可笑的 |
| 1539 | nullify | 使无效;废除;取消 |
| 1540 | valor | 英勇;勇气;英雄气概 |
| 1541 | whether or not pardon erase history | 赦免是否能抹去历史 |
| 1542 | DC US Attorney's Office | 美国华盛顿特区联邦检察官办公室 |
| 1543 | memo | 备忘录;便条;内部通知 |
| 1544 | blue | 蓝色;忧郁的;(政治)民主党的;黄色的(英式) |

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
85% confidence
Finding

Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Content

Scanner excerpt · asset/vocabulary_bank.md (reported line 1793)May include surrounding context.

md
| 1787 | cable tv hit | 有线电视热播节目 |
| 1788 | drew parallels | 做出类比;把...相提并论 |
| 1789 | preaching | 布道;说教;讲大道理 |
| 1790 | don't preach panic | 别散布恐慌;别大喊狼来了 |
| 1791 | getting a side eye from | 被...翻白眼;遭...侧目而视 |
| 1792 | creating lines in the sand | 划定底线;设定不可逾越的界限 |
| 1793 | overall arching point | 总体核心论点;贯穿全文的主旨 |

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill instructs running a local Python script and modifying workspace memory files, but it declares no explicit tool scope or permission boundaries. That creates an authorization gap: an agent may execute code and read/write files without clear, user-visible constraints, increasing the chance of unintended file access or broader-than-expected side effects.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill persistently updates /memory/review_log.md and even says to never skip that update, but it does not clearly warn the user before modifying long-lived workspace state. Persistent writes can surprise users, overwrite existing data conventions, or create privacy and integrity issues if the memory folder is reused across tasks or shared contexts.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The README states where persistent data is stored, including that it is outside the skill folder, but it does not clearly warn users that running the tool will modify review data in a shared workspace-level memory path. In an agent-skill context, unexpected writes outside the installation directory can surprise users, complicate auditing, and increase the chance of unintended persistence or cross-skill data interaction.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The activation instruction hard-codes Chinese trigger phrases (复习, 单词复习) in addition to English, but the skill does not explain the language policy or offer user opt-in for language/locale behavior. This can violate language/locale policy expectations when a skill assumes specific languages without documenting or negotiating that choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

This markdown file is a vocabulary list explicitly framed as 'English Vocabulary List' with Chinese translations, which establishes a fixed language pairing. Under the policy rule for natural-language violations, forcing a specific language without user opt-in can be a locale/language policy issue when no alternative or choice is provided.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.