Back to skill

Security audit

Discord Task Tracker

Security checks for vulnerabilities and agentic risk

Overview

This is a straightforward Discord task tracker that stores tasks locally, with some multi-user privacy and data-loss caveats but no hidden or malicious behavior found.

Reasonable to install for a personal or single-channel task list. Do not use it as a multi-user Discord task system without adding per-user or per-channel task ownership, escaping Discord-formatted task text, and making completion/deletion permanence clear.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/task_manager.py:16
Finding
Missing Task Ownership and Caller Isolation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/task_manager.py`, lines 16-77 **Vulnerability Type**: Missing authorization and tenant isolation **Risk Level**: High ### Complete Code Snippet ```python SKILL_DIR = Path(__file__).parent.parent TASKS_FILE = SKILL_DIR / "tasks.json" def load_tasks(): if TASKS_FILE.exists(): with open(TASKS_FILE, "r", encoding="utf-8") as f: return json.load(f) return [] def save_tasks(tasks): with open(TASKS_FILE, "w", encoding="utf-8") as f: json.dump(tasks, f, indent=2) def cmd_add(text): tasks = load_tasks() task_id = len(tasks) + 1 tasks.append({"id": task_id, "text": text.strip(), "done": False}) save_tasks(tasks) print(f"✅ Task added (#{task_id}): {text.strip()}") def cmd_list(): tasks = load_tasks() if not tasks: print("📋 No tasks yet. Say 'add task <description>' to create one.") return lines = ["**📋 Your Tasks:**"] for t in tasks: status = "✅" if t["done"] else "⬜" lines.append(f" {status} `[{t['id']}]` {t['text']}") print("\n".join(lines)) def cmd_complete(task_id): tasks = load_tasks() task = next((t for t in tasks if t["id"] == int(task_id)), None) if not task: print(f"❌ Task #{task_id} not found.") return task["done"] = True save_tasks(tasks) # Remove completed task tasks = [t for t in tasks if not (t["id"] == int(task_id))] save_tasks(tasks) print(f"✅ Task #{task_id} completed and removed: {task['text']}") def cmd_delete(task_id): tasks = load_tasks() task = next((t for t in tasks if t["id"] == int(task_id)), None) if not task: print(f"❌ Task #{task_id} not found.") return tasks = [t for t in tasks if t["id"] != int(task_id)] save_tasks(tasks) print(f"🗑️ Task #{task_id} deleted: {task['text']}") ``` ### Technical Analysis All commands read from and write to the same `tasks.json` file ...[truncated 1556 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pass trusted Discord context separately from user-controlled command text, including the authenticated user ID, guild ID, and channel ID. 2. Add explicit ownership and scope fields to each task, for example: ```python { "id": task_id, "owner_id": discord_user_id, "guild_id": discord_guild_id, "channel_id": discord_channel_id, "text": text, "done": False } ``` 3. Filter task listings by the authenticated owner and the intended guild/channel scope. 4. Before completing or deleting a task, retrieve it by both task ID and owner/scope rather than by task ID alone. 5. Do not accept identity fields from natural-language command content. Obtain them from trusted integration metadata. 6. Use globally unique identifiers or owner-scoped counters instead of `len(tasks) + 1`, which can produce duplicate IDs after deletion. 7. Add tests proving that one user cannot list, complete, or delete another user's tasks. 8. If shared task lists are intentional, define roles and enforce explicit read/write permissions for each shared list. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/task_manager.py:27
Finding
Stored Discord Content Injection Through Unescaped Task Text<![CDATA[ ## Vulnerability Details **File Location**: `scripts/task_manager.py`, lines 27-46, 61, and 77 **Vulnerability Type**: Unescaped user-controlled output **Risk Level**: Medium ### Complete Code Snippet ```python def cmd_add(text): tasks = load_tasks() task_id = len(tasks) + 1 tasks.append({"id": task_id, "text": text.strip(), "done": False}) save_tasks(tasks) print(f"✅ Task added (#{task_id}): {text.strip()}") def cmd_list(): tasks = load_tasks() if not tasks: print("📋 No tasks yet. Say 'add task <description>' to create one.") return lines = ["**📋 Your Tasks:**"] for t in tasks: status = "✅" if t["done"] else "⬜" lines.append(f" {status} `[{t['id']}]` {t['text']}") print("\n".join(lines)) ``` The same stored text is also emitted by completion and deletion responses: ```python print(f"✅ Task #{task_id} completed and removed: {task['text']}") ``` ```python print(f"🗑️ Task #{task_id} deleted: {task['text']}") ``` ### Technical Analysis Task descriptions are fully user-controlled. They are stored without validation and interpolated directly into output intended for a Discord channel. No escaping or neutralization is applied to Discord markdown, mentions, links, line breaks, control characters, or other presentation syntax. This creates a stored content-injection condition: one caller can save specially formatted content that is rendered again when tasks are listed, completed, or deleted. Depending on the Discord integration's message settings and bot permissions, injected content can produce misleading formatting, deceptive links, message-like content, or unwanted user, role, or mass mentions. Because the task text is persisted in `tasks.json`, the payload may affect users other than the original submitter whenever the shared task list is displayed. ### Attack Path 1. An attacker submits a task description containing Discord formatting or mention syntax, such as a dece ...[truncated 979 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Escape Discord markdown metacharacters before rendering task text. 2. Configure the Discord API client with restrictive allowed-mention settings, ideally disabling all mentions for task output unless explicitly required: ```python allowed_mentions = discord.AllowedMentions.none() ``` 3. If selected mentions are a legitimate feature, resolve and authorize them explicitly rather than forwarding raw mention syntax. 4. Remove or normalize carriage returns, newlines, bidirectional controls, and other non-printing characters that can alter message presentation. 5. Enforce a reasonable maximum task-description length both before storage and before rendering. 6. Consider rendering user content in a clearly delimited form, such as escaped plain text or a controlled embed field. 7. Apply output encoding at every sink, including add, list, completion, and deletion responses; validating only during insertion is insufficient for existing stored records. 8. Add tests covering markdown links, code fences, user and role mentions, `@everyone`, multiline content, and Unicode presentation-control characters. ]]>
Vulnerability Patterns
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill states it stores tasks in a local `tasks.json` file, which implies file read/write behavior, but it does not declare any `permissions` or `allowed-tools` scope. This creates an authorization and review gap: the runtime may permit broader file operations than users or reviewers expect, increasing the risk of unintended access to or modification of other files if the implementation is flawed or later changed.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The module docstring at L003-L004 says the skill manages tasks in a JSON file, and the command structure distinguishes 'complete task' from 'delete task'. However, cmd_complete marks the task done and then immediately removes it from the task list, making completion behave like deletion. This is an active contradiction between the documented/intended semantics of separate complete vs delete actions and the actual code path.

Missing User Warnings

Low
Confidence
85% confidence
Finding
This markdown file describes behaviors that remove tasks, including auto-removal after completion and explicit deletion, but it does not warn users that these actions modify stored data in `tasks.json` and may be hard to undo. For markdown files, missing warnings about behaviors affecting user data should be flagged when the description omits disclosure of those effects.

Static analysis

No suspicious patterns detected.