Back to skill

Security audit

ms-todo-sync

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says, but it stores Microsoft To Do login material locally without explicit file protections.

Install only if you are comfortable granting this skill read/write access to Microsoft To Do. Use it on a trusted single-user machine, avoid --debug unless necessary, treat exports as sensitive, review delete actions carefully, and consider protecting or removing ~/.mstodo_token_cache.json and ~/.mstodo_device_flow.json when done.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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

Error
Location
scripts/ms-todo-sync.py:58
Finding

OAuth Token and Device-Flow Caches Lack Explicit File Protections

Content
View full analysis

Vulnerability Details

File Location: scripts/ms-todo-sync.py:58-76, 123-125, 143-167
Vulnerability Type: Insecure storage of OAuth authentication material
Risk Level: High

Vulnerable Code

python
# Set cache file path
if cache_file is None:
    cache_file = os.path.join(Path.home(), ".mstodo_token_cache.json")
self.cache_file = cache_file

# Initialize token cache
self.cache = msal.SerializableTokenCache()
if os.path.exists(self.cache_file):
    with open(self.cache_file, "r") as f:
        self.cache.deserialize(f.read())

# Register cache saving on exit
atexit.register(self._save_cache)

def _save_cache(self):
    """Save token cache to file"""
    if self.cache.has_state_changed:
        with open(self.cache_file, "w") as f:
            f.write(self.cache.serialize())
python
# Save flow information for step 2 use
flow_cache_file = os.path.join(Path.home(), ".mstodo_device_flow.json")
with open(flow_cache_file, "w") as f:
    json.dump(flow, f)
python
try:
    with open(flow_cache_file, "r") as f:
        flow = json.load(f)
except Exception as e:
    print(f"✗ Failed to read flow information: {e}")
    return False

app = msal.PublicClientApplication(
    self.client_id,
    authority=self.authority,
    token_cache=self.cache
)

# Wait for user to complete authentication
result = app.acquire_token_by_device_flow(flow)

if "access_token" in result:
    self.access_token = result["access_token"]
    self._save_cache()
    print("✓ Authentication successful! Login information saved, you will be logged in automatically next time.")
    # Clear flow cache
    os.remove(flow_cache_file)
    return True

Technical Analysis

The serialized MSAL cache can contain reusable OAuth access and refresh tokens. The device-flow cache contains authentication-flow secrets needed to complete an in-progress login. Both files are ...[truncated 2457 chars]

Remediation
View remediation

Remediation Suggestions

  1. Create authentication files with owner-only permissions from the outset, such as mode 0600, rather than correcting permissions only after writing.
  2. Use secure atomic file creation and replacement. On supported platforms, open files with flags equivalent to O_CREAT, O_EXCL, O_WRONLY, and O_NOFOLLOW.
  3. Verify that any existing cache is a regular file owned by the current user and is not a symbolic link before reading or replacing it.
  4. Write serialized data to a securely created temporary file in the same directory, flush and synchronize it, and atomically replace the destination.
  5. Explicitly enforce mode 0600 on existing cache files before use.
  6. Delete ~/.mstodo_device_flow.json in a finally block after success, failure, expiration, cancellation, or interruption.
  7. Remove both token and device-flow caches during logout.
  8. Avoid including token values or complete flow objects in debug output, exceptions, or logs.
  9. Document that the cache contains sensitive reusable authentication material and should not be copied, shared, or committed to source control.

T08 · Insecure Dependencies

Warning
Location
requirements.txt:6
Finding

Unbounded Dependency Versions Permit Mutable Supply-Chain Resolution

Content
View full analysis

Vulnerability Details

File Location: requirements.txt:6-9; pyproject.toml:22-25; SKILL.md:39-43, 430-432
Vulnerability Type: Unpinned third-party dependencies and non-reproducible installation
Risk Level: Medium

Vulnerable Code

requirements.txt:

text
# Microsoft Authentication Library (MSAL) - for Azure AD authentication
msal>=1.34.0

# HTTP library for API requests
requests>=2.32.5

pyproject.toml:

toml
dependencies = [
    "msal>=1.34.0",
    "requests>=2.32.5",
]

The documented installation process executes dependency resolution directly:

bash
uv sync

# Alternative: Install dependencies with pip
pip install -r requirements.txt

Technical Analysis

Both dependencies use minimum-version constraints without exact versions, upper bounds, hashes, or a reviewed lockfile in the audited project. Each future installation may therefore resolve a different package version and transitive dependency graph.

This does not establish that msal or requests is currently malicious. The issue is that the reviewed source does not uniquely identify the code that will execute in the future. A compromised upstream release, compromised package-publisher account, or incompatible future version could be installed automatically while still satisfying the declared constraints.

The alternative pip install workflow can also modify the active or global Python environment when the operator has not activated an isolated environment, increasing the blast radius of a compromised package.

Attack Path

  1. An upstream dependency, transitive dependency, publisher account, or future release is compromised.
  2. The compromised version remains compatible with the broad minimum-version constraint.
  3. A user or Agent follows the documented instruction to run uv sync or pip install -r requirements.txt.
  4. The package manager resolves and installs the compromised re ...[truncated 935 chars]
Remediation
View remediation

Remediation Suggestions

  1. Generate and commit a reviewed uv.lock file containing exact direct and transitive dependency versions.
  2. For pip-based installation, provide a fully pinned requirements file with cryptographic hashes and install it using hash verification.
  3. Perform dependency updates through an explicit review process rather than resolving unrestricted future releases during routine execution.
  4. Run vulnerability and provenance checks when updating the lockfile.
  5. Require an isolated virtual environment and remove the documented global-environment installation alternative.
  6. Where operationally appropriate, constrain acceptable versions with reviewed upper bounds in addition to minimum versions.
  7. Ensure automated Agents do not update or regenerate the lockfile without user authorization and security review.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (20)

Instruction Override

High
Category
Prompt Injection
Confidence
70% confidence
Finding

This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 87)May include surrounding context.

md
client_secret: Client secret (optional, used for application flow)
            tenant_id: Tenant ID, default is "common"
            cache_file: Token cache file path (optional, default: ~/.mstodo_token_cache.json)
            debug: Enable debug mode to print API requests and responses (default: False)
        """
        self.client_id = client_id or self.DEFAULT_CLIENT_ID
        self.client_secret = client_secret

Instruction Override

High
Category
Prompt Injection
Confidence
70% confidence
Finding

This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Content

Scanner excerpt · scripts/ms-todo-sync.py (reported line 47)May include surrounding context.

python
client_secret: Client secret (optional, used for application flow)
            tenant_id: Tenant ID, default is "common"
            cache_file: Token cache file path (optional, default: ~/.mstodo_token_cache.json)
            debug: Enable debug mode to print API requests and responses (default: False)
        """
        self.client_id = client_id or self.DEFAULT_CLIENT_ID
        self.client_secret = client_secret

Instruction Override

High
Category
Prompt Injection
Confidence
70% confidence
Finding

This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Content

Scanner excerpt · scripts/ms-todo-sync.py (reported line 1186)May include surrounding context.

python
client_secret: Client secret (optional, used for application flow)
            tenant_id: Tenant ID, default is "common"
            cache_file: Token cache file path (optional, default: ~/.mstodo_token_cache.json)
            debug: Enable debug mode to print API requests and responses (default: False)
        """
        self.client_id = client_id or self.DEFAULT_CLIENT_ID
        self.client_secret = client_secret

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
97% confidence
Finding

The skill describes and directs use of capabilities that read/write local files and access the network, but it does not declare any explicit tool scope such as allowed-tools or permissions. This weakens policy enforcement and user awareness, making it easier for an agent to perform sensitive operations like exporting task data or storing tokens without an explicit least-privilege boundary.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 189)May include surrounding context.

md
| Argument/Option | Required | Description |
|-----------------|----------|-------------|
| `name` | Yes | Name of the list to delete |
| `-y, --yes` | No | Skip confirmation prompt |

> ⚠️ **This is a destructive operation**. Without `-y`, the command will prompt for confirmation. Consider asking the user before deleting important lists.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 247)May include surrounding context.

md
| Argument/Option | Required | Description |
|-----------------|----------|-------------|
| `name` | Yes | Name of the list to delete |
| `-y, --yes` | No | Skip confirmation prompt |

> ⚠️ **This is a destructive operation**. Without `-y`, the command will prompt for confirmation. Consider asking the user before deleting important lists.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · scripts/ms-todo-sync.py (reported line 1222)May include surrounding context.

python
| Argument/Option | Required | Description |
|-----------------|----------|-------------|
| `name` | Yes | Name of the list to delete |
| `-y, --yes` | No | Skip confirmation prompt |

> ⚠️ **This is a destructive operation**. Without `-y`, the command will prompt for confirmation. Consider asking the user before deleting important lists.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · scripts/ms-todo-sync.py (reported line 1250)May include surrounding context.

python
| Argument/Option | Required | Description |
|-----------------|----------|-------------|
| `name` | Yes | Name of the list to delete |
| `-y, --yes` | No | Skip confirmation prompt |

> ⚠️ **This is a destructive operation**. Without `-y`, the command will prompt for confirmation. Consider asking the user before deleting important lists.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 419)May include surrounding context.

md
- Lists will be auto-created if they don't exist, so feel free to use meaningful list names
4. **Destructive operations**: For `delete` and `delete-list` commands:
   - These commands will prompt for confirmation by default (blocking behavior)
   - Use `-y` flag to skip confirmation ONLY when:
     - User has explicitly requested to delete without confirmation
     - The deletion intent is unambiguous and confirmed through conversation
   - When in doubt, ask the user for confirmation instead of using `-y`

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 420)May include surrounding context.

md
4. **Destructive operations**: For `delete` and `delete-list` commands:
   - These commands will prompt for confirmation by default (blocking behavior)
   - Use `-y` flag to skip confirmation ONLY when:
     - User has explicitly requested to delete without confirmation
     - The deletion intent is unambiguous and confirmed through conversation
   - When in doubt, ask the user for confirmation instead of using `-y`
5. **Global option placement**: `-v` and `--debug` must come BEFORE the subcommand, not after.

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 475)May include surrounding context.

md
# Check existing lists first
uv run scripts/ms-todo-sync.py lists

# Add task to specific list (list auto-created if needed)
uv run scripts/ms-todo-sync.py add "Report" -l "Work" -p high -d 3 -D "Q4 financials"

# Add task to default list (no -l option)

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 478)May include surrounding context.

md
# Check existing lists first
uv run scripts/ms-todo-sync.py lists

# Add task to specific list (list auto-created if needed)
uv run scripts/ms-todo-sync.py add "Report" -l "Work" -p high -d 3 -D "Q4 financials"

# Add task to default list (no -l option)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Debug mode prints full request bodies and response bodies for Graph API operations, which may include task titles, notes, categories, reminder details, and potentially service error details. This creates a clear risk of sensitive data leakage into terminal scrollback, logs, CI output, or shell history capture systems.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/ms-todo-sync.py (reported line 213)May include surrounding context.

python
if method == "GET":
            response = requests.get(url, headers=headers)
        elif method == "POST":
            response = requests.post(url, headers=headers, json=data)
        elif method == "PATCH":
            response = requests.patch(url, headers=headers, json=data)
        elif method == "DELETE":

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The export command writes all task data, including titles, notes, reminders, and metadata, to a local JSON file without warning about sensitivity or setting restrictive file permissions. On shared systems or in synced/home directories, this can expose personal or business task content to other users or services.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The CLI documents --create-list as the control for whether a missing list should be created, but cmd_add creates the list whenever args.list is provided and not found. That mismatch can cause unintended remote state changes in the user's Microsoft To Do account, especially in automation where users rely on flags to prevent mutation.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency is specified with a lower bound only (msal>=1.34.0), which permits installation of any newer release and makes builds non-reproducible. While this is not an immediate exploit by itself, it increases supply-chain risk because different environments may resolve to different versions, including future versions with regressions or vulnerabilities.

Content

Scanner excerpt · requirements.txt (reported line 6)May include surrounding context.

text
# For reproducible builds, consider using 'pip freeze' or 'uv lock' to generate exact versions

# Microsoft Authentication Library (MSAL) - for Azure AD authentication
msal>=1.34.0

# HTTP library for API requests
requests>=2.32.5

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency is unpinned (requests>=2.32.5), so installations may pull different versions over time. In a skill that performs Microsoft Graph API authentication and task management over HTTP, this increases supply-chain and reliability risk because a future resolved version could introduce security issues or behavioral changes.

Content

Scanner excerpt · requirements.txt (reported line 9)May include surrounding context.

text
msal>=1.34.0

# HTTP library for API requests
requests>=2.32.5

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), 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

requests has multiple historical advisories, and because the manifest does not pin an exact version, it is impossible to verify from this file alone whether a safe release will be installed. The skill's network-facing use of HTTP and authentication makes dependency hygiene more important, since a vulnerable or misresolved requests version could affect credential handling or request security.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.