Back to skill

Security audit

Todo Accelerator

Security checks for vulnerabilities and agentic risk

Overview

This task-board automation skill is coherent, but it needs review because editable task names and notes can drive automatic agent work and can reach Markdown files outside the intended notes folder.

Review before installing if your workspace has shared or externally edited task boards. Use it only with trusted task inputs, choose a confined notes folder, avoid task names containing path characters, disable automatic heartbeat pickup unless you want unattended task execution, and prefer installing PyYAML in a pinned virtual environment.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T01 · Skill Instruction Hijacking

Error
Location
scripts/todo.py:429
Finding

Persistent Agent Instruction Hijacking Through Untrusted Task Content

Content
View full analysis

Vulnerability Details

File Location: scripts/todo.py:429-489, references/processing-work-on-todo.md:3-13, initialization.md:60-65
Vulnerability Type: Stored prompt injection through task metadata and note content
Risk Level: High

Vulnerable Code

scripts/todo.py:429-489:

python
# ── Build output (data fields only; instructions are in SKILL.md) ──
target_lines = _real_lines(sections.get("Target", ""))
inv_heading = get_investigation_heading(sections)
inv_lines = _real_lines(
    sections.get(inv_heading, "")
) if inv_heading else []

out: list[str] = []
out.append(f"## Working on: {selected['name']}")
out.append(f"Note: {note_path}")
out.append(f"Iteration: {new_iterate}")
out.append("")

targets = fm.get("target") or []
if isinstance(targets, str):
    targets = [targets]
if targets:
    out.append("### Expected Results")
    for t in targets:
        out.append(f"- {t}")
    out.append("")

out.append("### Unresolved Issues")
for item in unchecked:
    out.append(f"- [ ] {item}")
out.append("")

if target_lines:
    out.append("### Previous Results")
    for ln in target_lines:
        out.append(ln)
    out.append("")

inv_name = inv_heading or "Investigation and Problems"
if inv_lines:
    out.append(
        f"Previous findings are in the \"{inv_name}\" section of the note. "
        "Review before starting; record any new discoveries in the same section. "
        "Keep entries concise — facts and conclusions only, no filler."
    )
    out.append("")

assigned_agent = fm.get("assigned-agent")
if assigned_agent:
    out.insert(0, (
        f"⚠️ DELEGATION REQUIRED: This to-do is assigned to agent "
        f"\"{assigned_agent}\". Notify agent \"{assigned_agent}\" and "
        f"pass the task details below to it. The agent must follow the "
        f"todo-accelerator skill workflow to process this to-do."
    ))
    out.inser
...[truncated 3977 chars]
Remediation
View remediation

Remediation Suggestions

  1. Treat every task field and note section as untrusted data, including values that were previously produced by an Agent.
  2. Place untrusted values inside clearly delimited data blocks and explicitly instruct the Agent never to interpret content inside those blocks as commands, policy, delegation instructions, or tool-call authorization.
  3. Use a structured serialization format such as JSON with fixed fields instead of generating an instruction-style Markdown prompt.
  4. Validate assigned-agent against an administrator-controlled allowlist of known agent identifiers. Do not generate DELEGATION REQUIRED from an arbitrary note value.
  5. Require explicit user confirmation before delegation, external communication, execution, sensitive file access, or other consequential actions requested by task content.
  6. Apply prompt-injection screening to requirements, targets, and note sections. Suspicious content should be displayed for review rather than automatically processed.
  7. Avoid unconditional heartbeat processing of untrusted tasks. Heartbeats should identify a candidate task and request approval before acting when the task source is not trusted.
  8. Record provenance for each task and enforce stricter handling for externally supplied or collaboratively edited notes.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/todo.py:385
Finding

Filesystem Path Traversal Through Unsanitized Task Names

Content
View full analysis

Vulnerability Details

File Location: scripts/todo.py:333-340, scripts/todo.py:385-389, scripts/todo.py:506-510, scripts/todo.py:580-584
Vulnerability Type: Path traversal and unrestricted Markdown file access
Risk Level: High

Vulnerable Code

scripts/todo.py:333-340:

python
board_path = config["board"]
notes_dir = config["notes_folder"]
tmpl_path = config["template"]
name = args.name

if not board_path.exists():
    print(f"Error: board not found: {board_path}", file=sys.stderr)
    sys.exit(1)

scripts/todo.py:385-389:

python
# Write companion note
notes_dir.mkdir(parents=True, exist_ok=True)
note_path = notes_dir / f"{name}.md"
if note_path.exists():
    print(f"Note already exists: {note_path} (skipped)")
else:
    note_path.write_text(content, encoding="utf-8")

scripts/todo.py:506-510:

python
note_path = selected["note_path"]
if not note_path.exists():
    print(f"Error: note not found: {note_path}", file=sys.stderr)
    sys.exit(1)

fm, sections = parse_note(note_path)

scripts/todo.py:580-584:

python
name = args.name
completed = args.completed or []

note_path = notes_dir / f"{name}.md"
if not note_path.exists():

Similar unchecked path construction also occurs when candidate and pending-note paths are derived from board card names:

python
note_path = notes_dir / f"{card['name']}.md"

Technical Analysis

A task name is used directly as part of a filesystem path. The code does not reject path separators, traversal components such as .., absolute paths, control characters, or platform-specific path syntax. It also does not resolve the resulting path and verify that it remains inside the configured notes directory.

With a value such as ../../HEARTBEAT, the expression below can refer to a file outside notes_dir:

python
notes_dir / "../../HEARTBEAT.md"

The add-todo ...[truncated 2104 chars]

Remediation
View remediation

Remediation Suggestions

  1. Reject task names containing /, \, .., absolute-path syntax, NUL bytes, control characters, or platform-specific reserved filename characters.
  2. Convert display names to safe, generated filenames rather than using names directly. A random identifier or validated slug should be stored separately from the human-readable title.
  3. Resolve every destination before access and enforce containment:
python
candidate = (notes_dir / f"{safe_name}.md").resolve()
notes_root = notes_dir.resolve()
if not candidate.is_relative_to(notes_root):
    raise ValueError("Task note path escapes the notes directory")
  1. Apply the containment check before every note read, write, update, and existence check, including paths derived from board cards.
  2. Validate existing board card names before processing them because a board can be edited independently of add-todo.
  3. Consider opening new notes with exclusive creation semantics to prevent race conditions and unintended replacement.
  4. Add regression tests covering ../, nested traversal, absolute paths, backslash traversal, encoded-looking separators, control characters, and symlink-based escapes.
  5. If symlinks are permitted in the notes directory, verify the resolved final target rather than only validating the lexical path.

T08 · Insecure Dependencies

Warning
Location
initialization.md:8
Finding

Unpinned PyYAML Installation in the Active Python Environment

Content
View full analysis

Vulnerability Details

File Location: initialization.md:8-11
Vulnerability Type: Unpinned third-party dependency installation
Risk Level: Medium

Vulnerable Code

markdown
1. **Python 3** with **PyYAML** installed:
   ```bash
   pip3 install PyYAML
   ```

Technical Analysis

The initialization instructions install PyYAML without a version constraint, dependency lock file, integrity hash, isolated virtual environment, or explicitly trusted package index. The installed artifact is therefore determined by package-index state at setup time.

This is not evidence that PyYAML itself is malicious. The weakness is that builds are not reproducible and setup implicitly trusts whichever matching release and transitive installation artifacts are returned by the configured Python package index. Future package compromise, index misconfiguration, or an incompatible release could consequently affect the skill.

Because the command uses pip3 directly, it may also alter a shared or system-associated Python environment instead of a project-specific environment.

Attack Path

  1. An operator follows the documented prerequisite command.
  2. pip3 queries its configured package index for the current PyYAML release because no version or hash is specified.
  3. A compromised index account, unsafe mirror, index configuration, or future malicious release supplies an unexpected artifact.
  4. The artifact is installed into the active Python environment.
  5. The dependency's code executes when scripts/todo.py imports yaml, with the privileges of the Agent process.

Impact Assessment

A compromised dependency would execute with the same filesystem, network, and process privileges as the Python interpreter running the skill. This could affect all data accessible to that Agent environment. Even without malicious compromise, unconstrained upgrades can introduce incompatible parsing or serialization behavior and ...[truncated 35 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin PyYAML to a reviewed version in a requirements or lock file.
  2. Include cryptographic hashes and install with hash verification, for example through pip install --require-hashes -r requirements.txt.
  3. Use a dedicated virtual environment rather than installing into the active global Python environment.
  4. Document and enforce the trusted package index instead of relying on arbitrary local pip configuration.
  5. Add automated dependency scanning and a controlled process for reviewing and updating pinned versions.
  6. Record the supported Python and PyYAML versions so deployments remain reproducible.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (11)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill directs the agent to invoke a Python script and to write/update companion markdown notes, but it does not declare any explicit tool scope such as allowed-tools or permissions. That creates an authorization ambiguity where a host agent may grant broader file read/write access than users expect, increasing the chance of unintended workspace modification during routine task handling.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The activation description is very broad and includes common situations like user interest in a topic, heartbeat events, bookmarks, and help preparing deliverables. This can cause the skill to trigger without clear user intent, leading the agent to create, modify, or advance todos and associated files unexpectedly.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The initialization instructions direct the agent to run a command that creates a notes folder, copies a board template, and writes a configuration file to user-specified paths, but they do not explicitly require warning the user that files will be created or overwritten in those locations. In an agent context, this can lead to unintended filesystem modifications if the user does not fully understand the side effects or if ambiguous paths are provided.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The template requirements mandate specific non-English headings, including Chinese labels '推进中' and '审阅中', with no indication that the user can choose or opt into that locale. This is a natural-language locale constraint that appears undocumented and not justified as region-specific.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code injects Chinese default target text ("你期待的结果1", "你期待的结果2") when the user does not provide targets, which imposes a language choice without opt-in. That violates the language/locale policy because the skill does not offer a user language selection or document a justified locale constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill moves items to headings named "审阅中" and "推进中" and prints those labels to the user as part of normal operation. Because the file does not offer a language choice or explain that the tool is intentionally Chinese-localized, this is a natural-language locale policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The instructions hard-code workflow states using Chinese labels like '审阅中' and '推进中' without indicating that the user can choose the language or that the skill is region-specific. This creates a locale policy concern because the skill imposes a specific language in its natural-language workflow labels without documented user opt-in or justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

The template includes Chinese headings such as "推进中" and "审阅中" while other headings are in English. This creates a language/locale constraint in the skill artifact without any explanation, opt-in, or indication that the template is intended for a Chinese-speaking context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The markdown includes the status label "推进中" as part of the skill workflow, which imposes a non-English locale in user-facing behavior. The file does not indicate that this locale is optional, configurable, or required for a region-specific purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The output example moves the to-do to "审阅中", a Chinese-language state name, but the skill description does not explain or make this locale behavior optional. This can violate language/locale policy when users are not given an explicit choice.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The final case study again shows the skill moving items to "审阅中" with no accompanying language-selection mechanism or justification. Repeated default use of a fixed locale in user-visible outputs suggests a natural-language policy issue.

Content

No source excerpt is available for this finding.