Back to skill

Security audit

Linear Todos

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do what it says for Linear todos, but its install guidance and credential/profile-file handling create review-worthy risk.

Review before installing. Prefer an already installed uv or a package-manager install instead of curl | sh, use a dedicated minimal Linear API key, prefer LINEAR_API_KEY over saved plaintext config, set LINEAR_TIMEZONE explicitly if you do not want USER.md read, and add cron entries only if you intentionally want scheduled runs.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (4)

T03 · Remote Payload Retrieval and Execution

Error
Location
README.md:25
Finding

Remote Installer Is Downloaded and Executed Without Verification

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
src/linear_todos/config.py:169
Finding

Linear API Key Is Persisted in Plaintext Using a Non-Atomic Permission Sequence

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Note
Location
src/linear_todos/config.py:11
Finding

Skill Automatically Searches for and Reads an OpenClaw USER.md File

Content
View full analysis
Optional[str]: """Try to extract timezone from OpenClaw's USER.md if present. Searches up the directory tree from the skill location for a workspace containing USER.md, then parses the timezone field. """ # Start from the skill directory and search upward for workspace skill_dir = Path(__file__).resolve().parent current = skill_dir # Search up a few levels for workspace root for _ in range(5): user_md = current / "USER.md" if user_md.exists(): try: content = user_md.read_text() # Look for timezone: America/New_York or similar match = re.search(r'(?:timezone|time.?zone)\s*[:=]\s*["\']?([^\n"\']+)["\']?', content, re.IGNORECASE) if match: tz = match.group(1).strip() # Clean up common markdown/formatting artifacts tz = tz.split('(')[0].strip() # Remove " (EST/EDT)" suffix tz = tz.replace('*', '').strip() # Remove markdown asterisks # Validate it looks like a timezone (has a slash for region/city) if '/' in tz and not tz.startswith('http'): return tz except (IOError, OSError): pass break # Also check if we're in skills/ subdirectory of workspace if current.name == "skills": user_md = current.parent / "USER.md" if user_md.exists(): try: content = user_md.read_text() match = re.search(r'(?:timezone|time.?zone)\s*[:=]\s*["\']?([^\n"\']+)["\']?', content, re.IGNORECASE) if match: ...[truncated 2676 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
pyproject.toml:20
Finding

Dependency Installation Is Not Reproducibly Pinned

Content
View full analysis
=8.3.1", "dateparser>=1.3.0", "requests>=2.32.5", ] ``` The installation documentation at `README.md:34-38` resolves these dependencies: ```bash ### 2. Install Dependencies ```bash uv sync ``` ``` ### Technical Analysis The repository does not include a reviewed lockfile, and each runtime dependency uses an open-ended lower-bound constraint. As a result, separate executions of `uv sync` may resolve different package versions, including releases published after this audit. No currently declared dependency was shown to be malicious. The vulnerability is the lack of reproducibility and integrity pinning: if a dependency publisher account, package release, or package index is compromised, the resolver may install attacker-controlled code that was not part of the reviewed artifact. Python packages and their build backends may execute code during installation as well as at runtime. ### Attack Path 1. An attacker compromises a declared dependency's publishing account or distribution channel. 2. The attacker publishes a malicious version that satisfies the open-ended `>=` constraint. 3. A user runs the documented `uv sync` command without a reviewed lockfile. 4. The resolver selects and installs the malicious compatible release. 5. Package build or runtime code executes with the privileges of the user running the Skill. 6. The malicious dependency may access the Linear API key, configuration files, workspace data, and other resources available to that account. ### Impact Assessment Successful exploitation can lead to arbitrary code execution under the installing or invoking user's account. This could disclose the Linear API key and local files, alter Skill behavior, tamper with todo data, or establish persistence within the user's ...[truncated 171 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (26)

Chaining Abuse

High
Category
Tool Misuse
Confidence
98% confidence
Finding

The explicit shell pipe chaining pattern (curl ... | sh) is dangerous because it removes the opportunity for users to inspect what will execute and turns a network response directly into code execution. In the context of a source-execution skill, normalizing this pattern increases supply-chain and workstation compromise risk for users following setup instructions.

Content

Scanner excerpt · README.md (reported line 29)May include surrounding context.

bash
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Or with Homebrew
brew install uv

Session Persistence

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

md
### 3. Get a Linear API Key

1. Go to [linear.app/settings/api](https://linear.app/settings/api)
2. Create a new API key (name it "Linear Todos" or whatever you prefer)
3. Copy the key — you'll need it for the next step

### 4. Run Setup Wizard

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill is explicitly source-executing and documents capabilities to read environment variables, access files, write configuration, make network requests, and invoke shell commands, but it does not declare any explicit tool scope restrictions such as permissions or allowed-tools. That creates an avoidable trust gap: consumers must rely on documentation rather than enforceable platform constraints, so future code changes could expand behavior without corresponding policy controls.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% 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 55)May include surrounding context.

md
### Recommended Security Practices

1. **Use a dedicated API key:** Create a separate Linear API token with minimal scope for this skill. Revoke it if you uninstall or stop using the skill.
2. **Prefer environment variables:** Set `LINEAR_API_KEY` in your shell instead of running `setup` — no plaintext file is created.
3. **Audit the code:** Review `src/linear_todos/api.py` to verify HTTP destinations before first use.
4. **Run initial setup in isolation:** If unsure, run the skill in a container/VM for the first setup to inspect behavior.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% 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 166)May include surrounding context.

Natural Date Examples:

bash
uv run python main.py create "Task" --date "tomorrow"
uv run python main.py create "Task" --date "Friday"
uv run python main.py create "Task" --date "next Monday"
uv run python main.py create "Task" --date "in 3 days"

Session Persistence

Medium
Category
Rogue Agent
Confidence
86% confidence
Finding

The metadata explicitly states that the config file may store the Linear API key in plaintext JSON on disk, even though protected with 0o600 permissions and only written during manual setup. This is a real credential persistence risk: any local compromise of the user account, backups, accidental file exposure, or unsafe file handling could disclose the API key and enable unauthorized access to the user's Linear workspace.

Content

Scanner excerpt · _meta.json (reported line 55)May include surrounding context.

json
"sensitive": true,
    "autoWrite": false,
    "permissions": "0o600",
    "note": "Config file is written ONLY during manual 'setup' command with 0o600 permissions (user read/write only). Environment variables can be used instead to avoid persisted state."
  },
  "network": {
    "destinations": ["https://api.linear.app"],

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% 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 · cron-jobs.txt (reported line 4)May include surrounding context.

text
# Linear Todos Cron Jobs - EXAMPLE ONLY
# ======================================
# ⚠️  WARNING: This file contains EXAMPLE cron entries. It does NOT
#    automatically modify your crontab. Adding these is a manual
#    user action. Review before using.
#
# To add these jobs, run: crontab -e

Session Persistence

Medium
Category
Rogue Agent
Confidence
85% 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 69)May include surrounding context.

md
#    automatically modify your crontab. Adding these is a manual
#    user action. Review before using.
#
# To add these jobs, run: crontab -e
# Then paste the entries you want (modify paths first!)

SHELL=/bin/bash

Session Persistence

Medium
Category
Rogue Agent
Confidence
85% 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 · _meta.json (reported line 68)May include surrounding context.

json
#    automatically modify your crontab. Adding these is a manual
#    user action. Review before using.
#
# To add these jobs, run: crontab -e
# Then paste the entries you want (modify paths first!)

SHELL=/bin/bash

Session Persistence

Medium
Category
Rogue Agent
Confidence
85% 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 · cron-jobs.txt (reported line 7)May include surrounding context.

text
#    automatically modify your crontab. Adding these is a manual
#    user action. Review before using.
#
# To add these jobs, run: crontab -e
# Then paste the entries you want (modify paths first!)

SHELL=/bin/bash

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · SECURITY.md (reported line 10)May include surrounding context.

md
class LinearAPI:
    """Client for the Linear GraphQL API."""
    
    API_URL = "https://api.linear.app/graphql"
    
    def __init__(self, api_key: Optional[str] = None, config=None):
        """Initialize the Linear API client.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · SKILL.md (reported line 42)May include surrounding context.

md
class LinearAPI:
    """Client for the Linear GraphQL API."""
    
    API_URL = "https://api.linear.app/graphql"
    
    def __init__(self, api_key: Optional[str] = None, config=None):
        """Initialize the Linear API client.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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 · src/linear_todos/api.py (reported line 25)May include surrounding context.

python
class LinearAPI:
    """Client for the Linear GraphQL API."""
    
    API_URL = "https://api.linear.app/graphql"
    
    def __init__(self, api_key: Optional[str] = None, config=None):
        """Initialize the Linear API client.

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 · src/linear_todos/api.py (reported line 70)May include surrounding context.

python
if variables:
            payload["variables"] = variables
        
        response = requests.post(
            self.API_URL,
            headers=headers,
            json=payload,

External Script Fetching

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The README recommends piping a remote script directly into a shell, which executes unreviewed code fetched over the network. If the remote host, CDN path, or transport is compromised, users could run attacker-controlled code on their machine during installation.

Content

Scanner excerpt · README.md (reported line 29)May include surrounding context.

bash
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Or with Homebrew
brew install uv

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

This markdown file documents a setup flow that saves settings to ~/.config/linear-todos/config.json, immediately after collecting a Linear API key. The README does not warn users that credentials or other sensitive configuration may be written to disk, which is a privacy and system-safety relevant behavior for markdown under the missing user warnings rule.

Content

No source excerpt is available for this finding.

Excessive Permissions

Low
Category
Privilege Escalation
Confidence
80% confidence
Finding

Skill requests more permissions than appear necessary for its stated functionality. Review if elevated access is justified.

Content

Scanner excerpt · SECURITY.md (reported line 39)May include surrounding context.

}

text

**Permissions:** Created with user-only read/write (0o600).

### Setup Behavior
During interactive setup, the wizard temporarily sets `LINEAR_API_KEY` in the process environment to validate the API key before saving. This only occurs during the setup session and is not persisted beyond the setup process.

Tool Parameter Abuse

Low
Category
Tool Misuse
Confidence
15% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · SECURITY.md (reported line 55)May include surrounding context.

  1. Run in isolation first — If unsure, test in a container:
    bash
    docker run -it --rm -v $(pwd):/app python:3.12 bash
    cd /app && pip install -e . && python main.py setup
    

Vague Triggers

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This TOML manifest file is in scope for vague-trigger review. The description says the skill is "a powerful todo management system" with "smart date parsing," but it does not define any explicit invocation phrases, activation boundaries, or exclusions, making the skill scope broad and underspecified from a trigger/activation perspective.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: click has 1 known advisory(ies) (CVE-2026-7246 (Pallets Click, versions 8.3.2 and below, contain a command injection vulnerabili)), 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.

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.

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
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.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The inline note says secrets.choice used below for security scan compliance, but the function immediately below also imports random and never uses it. This is a documentation/code contradiction about implementation intent, even though the security impact is low because greeting selection does in fact use secrets.choice later.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill searches upward from its own directory and reads workspace-level USER.md files to infer a timezone, which expands its data access beyond what is necessary for todo management. Even though it only extracts a timezone-like value, this is still an undocumented cross-boundary read of user/workspace content and can violate least-privilege expectations in an agent skill.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.