Back to skill

Security audit

滴答清单任务管理工具

Security checks for vulnerabilities and agentic risk

Overview

This TickTick/Dida365 task skill matches its stated purpose, but needs review because it stores account tokens and task data in local plaintext and can modify or delete live account data.

Review before installing if the account contains sensitive tasks. Use it only for explicit TickTick/Dida365 requests, protect the .env, .dida-token.json, and .dida-cache.json files, and require clear confirmation before any create/update/complete/delete action, especially deletions.

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
auth.py:159
Finding

OAuth authorization flow lacks state validation

Content
View full analysis
None: # noqa: N802 parsed = urllib.parse.urlparse(self.path) params = urllib.parse.parse_qs(parsed.query) code = params.get("code", [None])[0] error = params.get("error", [None])[0] self.send_response(200) self.send_header("Content-Type", "text/html; charset=utf-8") self.end_headers() msg = "

Authorization successful

Return to the terminal.

" if error: self.server.auth_result = {"error": error} msg = f"

Authorization failed

Reason: {error}

" elif code: self.server.auth_result = {"code": code} else: self.server.auth_result = {"error": "missing_code"} msg = "

Error

No authorization code was received.

" self.wfile.write(msg.encode("utf-8")) ``` The corresponding authorization request is constructed without a `state` parameter: ```python def run_oauth_flow(authorization_code: str | None = None) -> None: """Run the complete OAuth authorization flow.""" client_id, client_secret = _require_oauth_client() port = int(os.environ.get("DIDA_CALLBACK_PORT", str(DEFAULT_CALLBACK_PORT))) redirect_uri = f"http://localhost:{port}/callback" if authorization_code: code = authorization_code else: auth_url = ( f"{OAUTH_BASE}/authorize?" + urllib.parse.urlencode({ "client_id": client_id, "scope": "tasks:write tasks:read", "redirect_uri": redirect_uri, "response_type": "code", }) ) print(f"\nOpen th ...[truncated 2446 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
auth.py:45
Finding

OAuth tokens and private task cache are stored without restrictive file permissions

Content
View full analysis
None: payload = dict(token_data) payload["obtained_at"] = int(time.time()) TOKEN_FILE.write_text( json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8", ) ``` Task and project cache storage in `cache.py`: ```python def save_cache(cache_data: dict[str, Any]) -> None: """Save cache data to a local file.""" try: with open(CACHE_FILE, "w", encoding="utf-8") as f: json.dump(cache_data, f, ensure_ascii=False, indent=2) except OSError: pass ``` ### Technical Analysis The Skill stores OAuth access and refresh tokens in `.dida-token.json` and stores task/project API responses in `.dida-cache.json`. Both are plaintext files created using the process's default file-creation permissions. Their resulting permissions depend on the user's `umask`. Under a permissive configuration, other local users may be able to read the files. Rewriting an existing file also preserves its previous mode, so changing the `umask` later does not repair a file that is already overly permissive. The token file is especially sensitive because a refresh token may provide continuing API access. The cache may contain private task titles, descriptions, tags, dates, project names, and other API-returned metadata. ### Attack Path 1. The user completes OAuth authorization, causing `save_token()` to create or rewrite `.dida-token.json`. 2. The user lists projects or tasks, causing `save_cache()` to create or rewrite `.dida-cache.json`. 3. The files receive permissions derived from the current `umask`, or retain previously permissive permissions. 4. Another local user or compromised process reads one or both files. 5. The a ...[truncated 953 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (28)

Tainted flow: 'request' from os.environ.get (line 93, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · auth.py (reported line 104)May include surrounding context.

python
)

    try:
        with urllib.request.urlopen(request) as response:
            return json.loads(response.read().decode("utf-8"))
    except urllib.error.HTTPError as exc:
        try:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · .env (reported line 2)May include surrounding context.

text
# 滴答清单 API 配置
# 复制此文件为 .env 并填入实际配置
# Python 版 skill 仅依赖标准库,无需额外安装包。

# OAuth 应用凭据(在 developer.dida365.com/manage 创建应用获取)

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 · .env (reported line 12)May include surrounding context.

text
# OAuth 回调端口(默认 18365)
# DIDA_CALLBACK_PORT=18365

# 手动填入 access token(优先级高于 .dida-token.json)
# DIDA_ACCESS_TOKEN=

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

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

2. 配置环境

bash
cp .env.example .env

编辑 .env 文件,填入你的凭据:

Lp1

High
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The file uses environment access, local file read/write, and network capabilities to handle OAuth credentials and tokens, but the finding indicates these capabilities are not declared in permissions. In an agent skill context, undeclared sensitive capabilities reduce auditability and can let a skill access secrets, persist tokens, and communicate externally beyond what users or the platform expect.

Content

No source excerpt is available for this finding.

Lp1

High
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The file uses environment access, local file read/write, and network capabilities to handle OAuth credentials and tokens, but the finding indicates these capabilities are not declared in permissions. In an agent skill context, undeclared sensitive capabilities reduce auditability and can let a skill access secrets, persist tokens, and communicate externally beyond what users or the platform expect.

Content

No source excerpt is available for this finding.

Lp1

High
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The file uses environment access, local file read/write, and network capabilities to handle OAuth credentials and tokens, but the finding indicates these capabilities are not declared in permissions. In an agent skill context, undeclared sensitive capabilities reduce auditability and can let a skill access secrets, persist tokens, and communicate externally beyond what users or the platform expect.

Content

No source excerpt is available for this finding.

Lp1

High
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The file uses environment access, local file read/write, and network capabilities to handle OAuth credentials and tokens, but the finding indicates these capabilities are not declared in permissions. In an agent skill context, undeclared sensitive capabilities reduce auditability and can let a skill access secrets, persist tokens, and communicate externally beyond what users or the platform expect.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · auth.py (reported line 25)May include surrounding context.

python
def load_env_file() -> None:
    env_path = Path(__file__).with_name(".env")
    if not env_path.exists():
        return

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

python
def get_access_token() -> str:
    """获取当前的 access token。"""
    # 优先从环境变量获取(手动设置模式)
    manual_token = os.environ.get("DIDA_ACCESS_TOKEN")
    if manual_token:

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

python
def get_access_token() -> str:
    """获取当前的 access token。"""
    # 优先从环境变量获取(手动设置模式)
    manual_token = os.environ.get("DIDA_ACCESS_TOKEN")
    if manual_token:

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

python
def get_access_token() -> str:
    """获取当前的 access token。"""
    # 优先从环境变量获取(手动设置模式)
    manual_token = os.environ.get("DIDA_ACCESS_TOKEN")
    if manual_token:

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

python
def get_access_token() -> str:
    """获取当前的 access token。"""
    # 优先从环境变量获取(手动设置模式)
    manual_token = os.environ.get("DIDA_ACCESS_TOKEN")
    if manual_token:

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · auth.py (reported line 85)May include surrounding context.

python
client_id = os.environ.get("DIDA_CLIENT_ID")
    client_secret = os.environ.get("DIDA_CLIENT_SECRET")
    if not client_id or not client_secret:
        raise RuntimeError("缺少 DIDA_CLIENT_ID 或 DIDA_CLIENT_SECRET。请在 .env 文件中配置。")
    return client_id, client_secret

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 · client.py (reported line 32)May include surrounding context.

python
@property
    def token(self) -> str:
        """获取并验证 Access Token。"""
        if self._token:
            return self._token
        return get_access_token()

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This markdown file describes creating, updating, deleting, and completing projects and tasks, but it does not include any warning that these commands will modify remote Dida365/TickTick data. For a skill description, omission of warnings about behaviors affecting user data or system integrity fits the missing user warnings category.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The documentation tells users to place a Client ID and Client Secret into a local environment file, but provides no warning to keep the file private or avoid committing it to version control. Because this behavior affects credential safety and privacy, the markdown should disclose the sensitivity of these values.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill description contains many broad trigger phrases such as TODO, inbox, task management, and everyday task-related wording that can match common user requests outside the user's explicit intent to use TickTick/Dida365. This can cause over-invocation of the skill, leading the agent to access or modify a connected third-party task account when the user may have meant a generic reminder or planning request instead.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

OAuth access and refresh tokens are written in plaintext to a predictable local file next to the code, with no permission hardening, encryption, or user warning. If the host is multi-user, the workspace is synced/backed up, or other components can read local files, these tokens can be stolen and used to access or modify the user's TickTick account.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The file's natural-language strings, including errors, prompts, and docstrings, are presented in Chinese only, which imposes a specific language on users. There is no opt-in, fallback, or documented justification that this skill is intended only for a Chinese-speaking or region-specific context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The file’s natural-language comments and docstrings are written in Chinese, including user-relevant descriptions such as cache expiration and cache loading behavior. This imposes a specific language context without any indication of user choice or documented locale justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The file's user-facing labels and descriptions are written in Chinese, and the CLI description and outputs do not appear to offer any language selection or opt-in. This can violate a language/locale policy when a skill forces a specific language for all users without a documented justification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The CLI performs project deletion immediately after parsing arguments, with no confirmation prompt, dry-run, or safety flag. In a task-management skill, projects and their contents are user data, so accidental invocation, argument confusion, or agent mis-execution can cause irreversible loss of tasks and metadata.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Task deletion is executed directly with no user warning or confirmation. Because this skill is designed for natural-language task management, mistaken parsing, wrong task/project IDs, or unintended agent actions could silently delete user tasks, making the lack of guardrails materially risky.

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 · client.py (reported line 18)May include surrounding context.

python
T = TypeVar("T")

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


class Dida365Client: