Back to skill

Security audit

Ticktick Skill For Power Users

Security checks for vulnerabilities and agentic risk

Overview

This TickTick CLI is mostly purpose-aligned, but it persists sensitive OAuth and browser-session credentials in plaintext and supports cookie-based file uploads and bulk task changes with limited guardrails.

Review this before installing if you plan to use attachments or agent automation. Treat the config file as highly sensitive, avoid putting real client secrets on the command line, do not store a TickTick browser session cookie unless attachment upload is necessary, and require explicit user approval before file uploads or bulk abandon operations.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
ticktick/cli.py:66
Finding

OAuth Client Secret Exposed Through Command-Line Arguments

Content
View full analysis
", help="TickTick OAuth client ID") auth_p.add_argument("--client-secret", dest="client_secret", metavar="", help="TickTick OAuth client secret") ``` The documented authentication workflow explicitly instructs users to provide the secret as a command-line argument: ```bash # SKILL.md:26-30 # Set credentials and start OAuth flow python -m ticktick.cli auth --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET ``` The manual workflow has the same issue: ```bash # SKILL.md:44-48 # Use manual mode on headless servers python -m ticktick.cli auth --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET --manual ``` ### Technical Analysis Secrets supplied as command-line arguments may be exposed through several local channels: - Interactive shell history files. - Process inspection utilities while the command is running. - Process accounting and endpoint-monitoring systems. - Terminal logging, command auditing, or support diagnostics. - Automation logs when the documented command is placed in scripts or CI jobs. The parser does not mask or securely prompt for `--client-secret`; it accepts the secret directly from the process argument vector. The documentation makes this unsafe interface the primary setup method, increasing the likelihood that users will persist real secrets in shell history. The OAuth client secret alone does not directly reveal the user's access token. However, its disclosure allows an attacker to imperson ...[truncated 1336 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
ticktick/auth.py:28
Finding

High-Privilege Browser Session Cookie Stored in Plaintext

Content
View full analysis
tuple[str, str]: config = load_config() if not config or not config.get("sessionCookie"): raise RuntimeError( "sessionCookie not found in config. " "Add it to ~/.clawdbot/credentials/ticktick-cli/config.json" ) return config["sessionCookie"], config.get("v2DeviceId", "clawagent00000000000001") ``` The configuration is serialized directly as plaintext JSON: ```python # ticktick/auth.py:28-40 def load_config() -> dict | None: try: return json.loads(CONFIG_FILE.read_text()) except (FileNotFoundError, json.JSONDecodeError): return None def save_config(config: dict) -> None: CONFIG_DIR.mkdir(parents=True, exist_ok=True) CONFIG_FILE.write_text(json.dumps(config, indent=2)) try: os.chmod(CONFIG_DIR, 0o700) os.chmod(CONFIG_FILE, 0o600) except OSError: pass ``` The reusable cookie is then transmitted to the legitimate TickTick API: ```python # ticktick/commands/attach.py:57-68 resp = requests.post( url, headers={ "Cookie": f"t={session_cookie}", "X-Device": x_device, "User-Agent": "Mozilla/5.0 (rv:145.0) Firefox/145.0", "Origin": "https://ticktick.com", "Referer": "https://ticktick.com/webapp/", }, files={"file": (file_name, file_bytes)}, ) ``` The documentation instructs users to extract the `t` cookie from a logged-in browser and place it in the configuration: ```markdown - Session cookie (`t` cookie from ticktick. ...[truncated 3114 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
  • Rogue AgentSelf-Modification, Session Persistence
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (23)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill is ներկայացված as an OAuth2-based TickTick CLI, but it also instructs use of browser session cookies and supports file uploads, both of which materially expand its security and privacy impact. This mismatch can cause users or agents to trust the skill with a lower-risk model than its actual behavior warrants, leading to credential exposure or unintended exfiltration of local files.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · ticktick/auth.py (reported line 50)May include surrounding context.

python
if not config:
        raise RuntimeError("Not authenticated. Run 'ticktick auth' to set up credentials.")
    if not config.get("accessToken"):
        raise RuntimeError("No access token found. Run 'ticktick auth' to authenticate.")

    # Check expiry with 5-minute buffer (timestamps stored as JS milliseconds)
    expiry = config.get("tokenExpiry")

Tainted flow: 'file_bytes' from pathlib.Path.read_bytes (line 51, file read) → requests.post (network output)

High
Category
Data Flow
Confidence
80% confidence
Finding

File contents flow to a network sink. This may indicate data exfiltration of sensitive files.

Content

Scanner excerpt · ticktick/commands/attach.py (reported line 57)May include surrounding context.

python
x_device = json.dumps({"platform": "web", "version": 6430, "id": v2_device_id})

        # Do NOT set Content-Type — requests sets it with the multipart boundary automatically
        resp = requests.post(
            url,
            headers={
                "Cookie": f"t={session_cookie}",

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill documents capabilities that require shell, network, file read, and file write access, but it does not declare any tool scope or permissions boundaries. In an agent environment, this increases the chance of overbroad execution and unintended access because the runtime cannot constrain the skill to the minimum required privileges.

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

md
### 2. Register a TickTick Developer App

1. Go to [TickTick Developer Center](https://developer.ticktick.com/manage)
2. Create a new application
3. Set the redirect URI to `http://localhost:8080`
4. Note your `Client ID` and `Client Secret`

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The documented complete, abandon, and batch-abandon operations change remote task state and may be hard to reverse, but the skill does not prominently warn about their destructive or user-data-impacting effects. In an agent setting, omission of such warnings raises the risk of accidental mass modification of a user's task data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The attachment instructions explain how to upload local files to TickTick, but they do not clearly warn that local file contents will be transmitted to a third-party service. Without a privacy warning, an agent or user may upload sensitive local data without realizing the disclosure boundary.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manual cookie-handling workflow instructs users to extract and store a live browser session cookie, which is effectively bearer-token account access, but the warning is not strong enough for the sensitivity involved. Exposure of that cookie could let another party act as the user in the web session context, especially for APIs outside the OAuth scope.

Content

No source excerpt is available for this finding.

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

md
from .auth import get_valid_token

API_BASE = "https://api.ticktick.com/open/v1"

PRIORITY_MAP = {"none": 0, "low": 1, "medium": 3, "high": 5}
PRIORITY_REVERSE = {0: "none", 1: "low", 3: "medium", 5: "high"}

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

md
from .auth import get_valid_token

API_BASE = "https://api.ticktick.com/open/v1"

PRIORITY_MAP = {"none": 0, "low": 1, "medium": 3, "high": 5}
PRIORITY_REVERSE = {0: "none", 1: "low", 3: "medium", 5: "high"}

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

md
from .auth import get_valid_token

API_BASE = "https://api.ticktick.com/open/v1"

PRIORITY_MAP = {"none": 0, "low": 1, "medium": 3, "high": 5}
PRIORITY_REVERSE = {0: "none", 1: "low", 3: "medium", 5: "high"}

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

python
from .auth import get_valid_token

API_BASE = "https://api.ticktick.com/open/v1"

PRIORITY_MAP = {"none": 0, "low": 1, "medium": 3, "high": 5}
PRIORITY_REVERSE = {0: "none", 1: "low", 3: "medium", 5: "high"}

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 · ticktick/auth.py (reported line 19)May include surrounding context.

python
from .auth import get_valid_token

API_BASE = "https://api.ticktick.com/open/v1"

PRIORITY_MAP = {"none": 0, "low": 1, "medium": 3, "high": 5}
PRIORITY_REVERSE = {0: "none", 1: "low", 3: "medium", 5: "high"}

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 · ticktick/commands/attach.py (reported line 53)May include surrounding context.

python
from .auth import get_valid_token

API_BASE = "https://api.ticktick.com/open/v1"

PRIORITY_MAP = {"none": 0, "low": 1, "medium": 3, "high": 5}
PRIORITY_REVERSE = {0: "none", 1: "low", 3: "medium", 5: "high"}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

This code performs state-changing operations on user task data, including marking tasks complete and permanently deleting tasks, but these methods contain no confirmation prompt, print/log disclosure, or inline comment/docstring warning. In a code-file review, destructive or user-data-affecting actions should have some visible disclosure unless clearly covered elsewhere; no such warning is present in this file.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill stores the OAuth client secret persistently in a local JSON config file. Even with chmod 0600, storing long-lived secrets on disk increases exposure to local compromise, backups, sync tools, or accidental disclosure, especially on systems where filesystem permissions are weak or ignored.

Content

No source excerpt is available for this finding.

Tainted flow: 'auth_code' from input (line 253, user input) → requests.post (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · ticktick/auth.py (reported line 105)May include surrounding context.

python
).decode()
    redirect_uri = config.get("redirectUri", DEFAULT_REDIRECT_URI)

    resp = requests.post(
        f"{OAUTH_BASE}/token",
        headers={
            "Authorization": f"Basic {credentials}",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Access and refresh tokens are saved to disk, and the refresh token in particular can grant ongoing access if stolen. Although file permissions are tightened, local storage of bearer credentials creates a real risk of account compromise from malware, shared machines, insecure backups, or credential harvesting by other local processes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This code performs a network upload of user-selected file bytes to TickTick and includes the session cookie in request headers. While the final success message confirms completion, there is no prior disclosure via prompt, warning comment/docstring, or explicit user-facing notice in this file that local file contents and auth context will be sent to a remote service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code issues a batch update that marks tasks as abandoned by setting their status to -1, which is a destructive or potentially hard-to-reverse operation. While the command prints results afterward, there is no confirmation prompt or explicit warning before executing the abandonment action.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The call to complete the task marks user data as completed, which is a state-changing operation. While the command prints a success message afterward, there is no confirmation prompt, no pre-action warning, and no inline comment or docstring disclosing the effect before the change occurs.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: setuptools has 10 known advisory(ies) (CVE-2013-1633 (Setuptools vulnerable to Man-in-the-middle attacks); CVE-2025-47273 (setuptools has a path traversal vulnerability in PackageIndex.download that lead); CVE-2024-6345 (setuptools vulnerable to Command Injection via package URL) +7 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding

The build dependency setuptools>=68 is also unpinned, which makes the build environment non-reproducible and prevents verification that only non-vulnerable versions are used. Although this is primarily a build-time risk rather than a runtime flaw, compromised or vulnerable packaging tooling can still affect package installation or build processes.

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
94% confidence
Finding

The dependency specification requests>=2.31 is not pinned to a specific version, so builds may resolve to different releases over time and it is not possible to verify from this file alone whether a vulnerable version could be installed. In a CLI that performs OAuth2-authenticated network operations, a vulnerable HTTP client library could affect credential handling, request integrity, or transport security depending on the resolved version and execution environment.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.