Back to skill

Security audit

Ticktick Cli

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a real TickTick task-management integration, but it stores and uses powerful TickTick credentials and session cookies in ways that need careful review before installation.

Install only if you are comfortable granting this skill read/write access to your TickTick tasks and projects. Treat the config file and sessionCookie as sensitive account credentials, avoid pasting real secrets into command lines where logs or shell history may retain them, and manually confirm task IDs before completion, abandonment, batch operations, or attachment uploads.

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:67
Finding

OAuth Client Secret Exposed Through Command-Line Arguments

Content
View full analysis

Vulnerability Details

File Location: ticktick/cli.py:29-31, ticktick/cli.py:67-68, SKILL.md:53-59
Vulnerability Type: Sensitive information exposure through process arguments
Risk Level: Medium

Vulnerable Code

python
if args.client_id and args.client_secret:
    setup_credentials(args.client_id, args.client_secret)
python
auth_p.add_argument("--client-id", dest="client_id", metavar="<id>", help="TickTick OAuth client ID")
auth_p.add_argument("--client-secret", dest="client_secret", metavar="<secret>", help="TickTick OAuth client secret")

The documented workflow explicitly instructs users to supply the secret in the command line:

bash
python -m ticktick.cli auth --client-id <YOUR_CLIENT_ID> --client-secret <YOUR_CLIENT_SECRET>

python -m ticktick.cli auth --client-id <ID> --client-secret <SECRET> --manual

Technical Analysis

Command-line arguments are not an appropriate transport for confidential values. Depending on the operating system and environment, arguments may be exposed through:

  • Shell history files.
  • Process-listing tools while the command is running.
  • Process accounting or endpoint telemetry.
  • Terminal session recording.
  • Automation logs, CI output, or command wrappers.
  • Agent execution traces that retain the complete command.

The client secret is legitimately required for this OAuth client, but accepting it exclusively through an ordinary argparse option unnecessarily expands its exposure. The issue is particularly relevant for an Agent Skill because command invocations may be logged or retained outside the CLI itself.

Attack Path

  1. A user or Agent follows the authentication instructions in SKILL.md.
  2. The OAuth client secret is included literally in the command's argument vector.
  3. The command is retained in shell history, execution telemetry, process accounting, or an Agent log.

...[truncated 908 chars]

Remediation
View remediation

Remediation Suggestions

  • Replace the ordinary --client-secret argument with an interactive hidden prompt using getpass.getpass().
  • If noninteractive operation is required, accept the secret through a protected file descriptor, an operating-system keyring, or a narrowly scoped secret-manager integration.
  • Avoid environment variables as the default because they may also be exposed through process environments, crash reports, or automation logs.
  • If backward compatibility requires retaining --client-secret, mark it as deprecated and display a warning that it may expose the value through process metadata and command history.
  • Update README.md and SKILL.md so examples never place real secrets directly in command lines.
  • Advise existing users to remove commands containing secrets from shell history and rotate secrets if they may have been logged.
  • Ensure Agent integrations redact secret-bearing arguments from invocation logs and traces.

T09 · Insecure Skill Coding Practices

Warning
Location
ticktick/auth.py:29
Finding

Plaintext Credential Bundle Uses Fail-Open Permission Hardening

Content
View full analysis

Vulnerability Details

File Location: ticktick/auth.py:15-16, ticktick/auth.py:29-42, ticktick/auth.py:90-96, ticktick/commands/attach.py:13-20
Vulnerability Type: Insecure storage of sensitive authentication material
Risk Level: Medium

Vulnerable Code

python
CONFIG_DIR = Path.home() / ".clawdbot" / "credentials" / "ticktick-cli"
CONFIG_FILE = CONFIG_DIR / "config.json"
python
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
python
def setup_credentials(client_id: str, client_secret: str) -> None:
    config = load_config() or {}
    config["clientId"] = client_id
    config["clientSecret"] = client_secret
    config["redirectUri"] = DEFAULT_REDIRECT_URI
    save_config(config)
    print("Credentials saved successfully.")
python
def _get_session_config() -> 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 same JSON configuration can contain the OAuth client secret, access token, refresh token, and TickTick browser session cookie.

Technical Analysis

save_config() serializes all configuration fields as plaintext. The file is written before restrictive permissions are explicitly applied. Its initial permissions therefore depend on the current process umask and filesystem behavior.

The subsequent chmod operations are wrapped in a broad except OSError block that silently ignores all failures. The program can co ...[truncated 2616 chars]

Remediation
View remediation

Remediation Suggestions

  • Store the client secret, refresh token, access token, and session cookie in an operating-system keyring or dedicated secret manager.
  • If file storage is unavoidable, create the file with mode 0600 from the outset using low-level atomic file creation rather than writing first and changing permissions afterward.
  • Create and verify the credential directory with mode 0700.
  • Write updates to a securely created temporary file in the same protected directory, flush and synchronize it, then atomically replace the destination.
  • Reject symbolic links and verify that the destination is a regular file owned by the current user.
  • Verify final directory and file modes after creation.
  • Treat any failure to establish ownership or permissions as a fatal error; do not silently catch and ignore OSError.
  • Store the browser session cookie separately from OAuth client credentials and tokens to reduce the impact of a single-file compromise.
  • Remove the session cookie automatically when attachment functionality is disabled or the user logs out, or provide a dedicated command to clear it.
  • Avoid printing credential values in diagnostics and redact server responses where they could contain authentication details.
  • Document the plaintext-storage risk and advise users to rotate exposed tokens or cookies if file permissions were ever incorrect.
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (21)

Credential Access

High
Category
Privilege Escalation
Confidence
83% confidence
Finding

This module stores and retrieves long-lived OAuth secrets, including access tokens, refresh tokens, and the client secret, from a plaintext JSON file in the user's home directory. Although file permissions are tightened best-effort, the secrets remain recoverable by local compromise, backups, malware running as the same user, or misconfigured filesystems, which could allow unauthorized access to the user's TickTick account.

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}",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This markdown file describes abandoning tasks, including bulk abandonment, which can alter or remove task state in a potentially irreversible way. The surrounding documentation gives usage examples but does not warn users about the destructive nature of the operation or advise caution before running it.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The README instructs users to extract a live browser session cookie and place it into a local config file without warning that this credential can grant account access if stolen. Encouraging manual handling of session tokens increases the risk of credential leakage through shell history, screenshots, backups, or insecure file permissions, especially because session cookies are often equivalent to active authentication.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill documents capabilities that imply shell execution, filesystem access, and network use, but it declares no explicit tool scope or permission boundaries. In an agent environment, this increases the chance the skill will be invoked with broader authority than necessary, enabling unintended command execution, local file access, or credential handling beyond the user’s expectations.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger keywords are very broad and overlap with normal task-management language in both English and Chinese, making accidental activation more likely. In a skill that can authenticate, modify tasks, upload attachments, and perform destructive actions, overbroad routing can cause the wrong skill to handle user intents and execute unintended state-changing operations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill advertises abandon and batch-abandon operations without a prominent warning that they are destructive and may be hard to reverse. In an agent setting, this can lead to accidental bulk task state changes from ambiguous prompts or mis-selection of tasks, causing loss of workflow integrity and user trust.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The attachment workflow instructs use of a web session cookie (t) and device identifier outside normal OAuth, but it does not clearly warn that these are sensitive session secrets that can grant account access if exposed. Combining file upload, cookie handling, and plaintext config storage materially raises the risk of credential leakage, account compromise, and privacy exposure of attached files.

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

python
from .auth import get_valid_token

API_BASE = "https://api.dida365.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.dida365.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
84% confidence
Finding

The delete_task method performs an irreversible DELETE request against the remote task service, but this function contains no confirmation prompt, warning, or explanatory comment indicating the destructive effect. In a code file, destructive operations should have some visible disclosure unless the warning is provided elsewhere as part of the skill's stated behavior.

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

The command reads a session cookie from a local credentials file and uses it to authenticate requests, but this file provides no user-facing warning, prompt, or explanatory comment that a stored credential will be accessed. For code-file warning checks, access to sensitive environment variables or credentials should have some visible disclosure unless clearly covered elsewhere.

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

python
file_name = file_path.name
        file_bytes = file_path.read_bytes()

        url = f"https://api.ticktick.com/api/v1/attachment/upload/{project_id}/{task['id']}/{attachment_id}"
        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

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code transmits the contents of a local file to the TickTick API using a multipart HTTP POST, but there is no confirmation prompt or prior user-facing disclosure in the file that local file data will be sent to a remote service. Although attachment behavior is implied by the command name, the code itself lacks an explicit warning or explanatory comment about the network transmission of user data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The call to complete_task marks a task as completed, which changes user data and may be hard to notice or reverse in this command path. The file provides only a success message after the action, but no confirmation prompt, pre-action warning, or explanatory comment/docstring disclosing the state-changing behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file presents all user-facing instructions in Chinese, which effectively enforces a single language for this skill's documentation. Under the policy, language constraints should be optional, user-selectable, or explicitly justified if region-specific.

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
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: wheel has 4 known advisory(ies) (CVE-2026-24049 (Wheel Affected by Arbitrary File Permission Modification via Path Traversal in w); CVE-2022-40898 (pypa/wheel vulnerable to Regular Expression denial of service (ReDoS)); CVE-2022-40898 (An issue discovered in Python Packaging Authority (PyPA) Wheel 0.37.1 and earlie) +1 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: 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.