Back to skill

Security audit

Omnifocus4

Security checks for vulnerabilities and agentic risk

Overview

This OmniFocus skill is mostly purpose-aligned, but it asks agents to run unsandboxed commands and has an unprotected persistent setting that can disable write protections for destructive task changes.

Install only if you are comfortable giving the skill live access to your OmniFocus database and running its local automation outside the normal sandbox. Treat write actions as sensitive, avoid `prefs set yolo`, and prefer per-action confirmation before delete, move, rename, note replacement, or date changes.

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)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/omnifocus.py:968
Finding

Write authorization can be persistently disabled through an unprotected preferences command

Content
View full analysis
None: sub = args[0] if args else "show" if sub == "show": _out(_load_prefs()) elif sub == "set": if len(args) < 2: _err("Usage: prefs set ") mode = args[1] if mode not in ("yolo", "once", "every"): _err(f"Invalid mode: {mode}. Use: yolo, once, every") prefs = _load_prefs() prefs["mode"] = mode _save_prefs(prefs) _ok(mode=mode) ``` The authorization guard is applied only to commands contained in `WRITE_COMMANDS`: ```python cmd = argv[0] args = argv[1:] # Auth guard — outside try/except so exit(2) is never swallowed as an error. if cmd in WRITE_COMMANDS: _require_auth(cmd, authorized) try: if cmd == "inbox": cmd_inbox() ``` The `prefs` command is not included in `WRITE_COMMANDS`: ```python WRITE_COMMANDS = frozenset({ "add", "newproject", "newfolder", "newtag", "complete", "uncomplete", "delete", "rename", "note", "setnote", "defer", "due", "flag", "tag", "untag", "move", "repeat", "unrepeat", }) ``` ### Technical Analysis The application implements three authorization modes: - `once`: write commands must be approved by command name. - `every`: each write invocation must include `--authorized`. - `yolo`: all write operations are allowed without additional authorization. However, changing the authorization mode is itself not treated as a protected operation. Any caller capable of invoking the CLI can run `prefs set yolo` without satisfying the existing authorization policy. The resulting preference is persisted to `~/.omnifocus4/prefs.json`, after which `_require_auth()` immediately permits every write comman ...[truncated 1958 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
SKILL.md:15
Finding

Skill instructions require execution with sandbox protections disabled

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (13)

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

The skill description under-represents its capabilities: beyond simple live queries, it documents destructive and administrative actions such as delete, move, rename, note replacement, due/defer changes, and creating projects, folders, and tags. This mismatch can cause an orchestrating agent or user to trust the skill as informational while it is actually capable of modifying or deleting OmniFocus data.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The metadata uses extremely broad activation language such as 'Use for ANY OmniFocus query' and 'Always run a command,' which encourages automatic tool execution for loosely related requests. Overbroad triggers increase the chance of unintended access to sensitive personal task data or unintended modifications when the user's request is ambiguous.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The instruction says not to ask clarifying questions and to 'Just run the appropriate command,' removing a key safety control for ambiguous or risky requests. In a skill that supports deletion, completion, renaming, and other mutations, this can directly lead to unintended state changes or privacy exposure without verifying user intent.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill instructs the agent to invoke shell commands and perform state-changing operations, but it declares no explicit tool scope or permission boundary. Without allowed-tools/permissions metadata, an agent may execute broader shell or file-capable actions than intended, reducing auditability and increasing the blast radius if the skill is triggered unexpectedly or composed with other prompts.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documented command set includes destructive and modifying operations such as delete, complete, rename, setnote, move, due, and repeat configuration, but the skill provides no warning, approval flow, or confirmation guidance. This makes accidental or induced destructive actions more likely, especially because earlier sections encourage immediate execution without clarification.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% 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 · SKILL.md (reported line 72)May include surrounding context.

md
| Command | Args | Description |
|---------|------|-------------|
| `add` | `<name> [project]` | Add task to inbox or project |
| `newproject` | `<name> [folder]` | Create project |
| `newfolder` | `<name>` | Create top-level folder |
| `newtag` | `<name>` | Create or get tag |

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% 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 · SKILL.md (reported line 136)May include surrounding context.

md
| Command | Args | Description |
|---------|------|-------------|
| `add` | `<name> [project]` | Add task to inbox or project |
| `newproject` | `<name> [folder]` | Create project |
| `newfolder` | `<name>` | Create top-level folder |
| `newtag` | `<name>` | Create or get tag |

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% 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 · SKILL.md (reported line 139)May include surrounding context.

md
| Command | Args | Description |
|---------|------|-------------|
| `add` | `<name> [project]` | Add task to inbox or project |
| `newproject` | `<name> [folder]` | Create project |
| `newfolder` | `<name>` | Create top-level folder |
| `newtag` | `<name>` | Create or get tag |

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/omnifocus.py (reported line 101)May include surrounding context.

python
def run_osascript(script: str) -> str:
    """Run an AppleScript string and return stdout. Raises RuntimeError on failure."""
    try:
        proc = subprocess.run(
            ["osascript", "-e", script],
            capture_output=True,
            text=True,

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The test dependency is specified as pytest>=8.0 without an upper bound or exact pin, which makes builds non-reproducible and can allow an unexpectedly vulnerable or breaking future version to be installed. In this skill context, the risk is somewhat limited because this is a test-only requirement rather than a production runtime dependency, but it still weakens supply-chain hygiene and version assurance.

Content

Scanner excerpt · requirements-test.txt (reported line 1)May include surrounding context.

text
pytest>=8.0

Unverifiable Dependency: pytest has 2 known advisory(ies) (CVE-2025-71176 (pytest has vulnerable tmpdir handling); CVE-2025-71176 (pytest has vulnerable tmpdir handling)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
88% confidence
Finding

Because pytest is not pinned, it is impossible to verify from this manifest whether the installed version includes known advisories or a patched release. The danger here is indirect: downstream environments may resolve to a vulnerable version, especially in CI or shared development systems; however, the impact is reduced by this being a test dependency rather than code used directly by the OmniFocus skill at runtime.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

The manifest emphasizes live OmniFocus access and says to always run a command to get live data, suggesting the skill's purpose is interacting with OmniFocus itself. This file additionally reads and writes ~/.omnifocus4/prefs.json to manage authorization modes and remembered approvals, which is behavior outside the stated OmniFocus data/task management scope.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The comment says the function avoids document.flattenedTasks for speed and iterates project.tasks one project at a time, but the code then sets const col = flattenedTasks and loops over that collection. This is a direct contradiction between inline documentation and actual behavior.

Content

No source excerpt is available for this finding.