Back to skill

Security audit

Dingtalk Attendance

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its stated DingTalk attendance purpose, but it stores identifiable employee attendance history locally without adequate retention, deletion, or permission controls.

Review before installing in any real workplace. Use only with authorized HR or attendance-admin credentials scoped to the minimum DingTalk permissions. Treat the generated cache.db as sensitive employee data, restrict filesystem access to it, decide a retention policy, and add or require a purge/no-history option before routine use.

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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/attendance_query.py:17
Finding
Plaintext and Indefinite Local Storage of Employee Attendance Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/attendance_query.py`, lines 17-101 **Vulnerability Type**: Sensitive data stored without access-control or retention safeguards **Risk Level**: Medium ### Vulnerable Code ```python DEFAULT_CACHE_DB_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "cache.db") DEFAULT_CACHE_TTL_SECONDS = 7 * 24 * 3600 # 7 days def _get_cache_conn(db_path: str = DEFAULT_CACHE_DB_PATH) -> sqlite3.Connection: conn = sqlite3.connect(db_path) conn.execute( """ CREATE TABLE IF NOT EXISTS kv_cache ( key TEXT PRIMARY KEY, value TEXT NOT NULL, ts REAL NOT NULL ) """ ) conn.execute( """ CREATE TABLE IF NOT EXISTS attendance_history ( work_date TEXT NOT NULL, user_id TEXT NOT NULL, user_name TEXT NOT NULL, result_type TEXT NOT NULL, count INTEGER NOT NULL, queried_at REAL NOT NULL, PRIMARY KEY (work_date, user_id, result_type) ) """ ) conn.commit() return conn def _save_attendance_history( fail_table: Dict[str, "collections.Counter"], user_names: Dict[str, str], work_date: str, db_path: str = DEFAULT_CACHE_DB_PATH, ) -> None: """Save abnormal attendance records in the attendance_history table.""" conn = _get_cache_conn(db_path) try: now = time.time() for userid, counter in fail_table.items(): name = user_names.get(userid, userid) for result_type, count in counter.items(): conn.execute( """INSERT OR REPLACE INTO attendance_history (work_date, user_id, user_name, result_type, count, queried_at) VALUES (?, ?, ?, ?, ?, ?)""", (work_date, userid, name, result_type, count, now), ) conn.comm ...[truncated 2687 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store the database in a dedicated per-user application-data directory rather than beside the script. 2. Create the containing directory with mode `0700` and enforce database permissions of `0600` immediately after creation. 3. Refuse to use a database file that is owned by another user or has unsafe permissions. 4. Add a configurable retention period for `attendance_history` and delete records older than that period. 5. Minimize stored fields. Avoid retaining stable user IDs or names when aggregate results are sufficient. 6. Make historical persistence opt-in, or provide a `--no-history` option for one-time queries. 7. Add an explicit command to purge all cached identifiers and attendance history. 8. Exclude `cache.db`, SQLite journal files, and backup copies from source control, build artifacts, and Skill packaging. 9. Document the exact fields retained, their retention duration, and the local parties that may access them. 10. Where the deployment threat model includes untrusted local users or broadly accessible backups, encrypt sensitive records using keys stored separately from the database. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (14)

Context-Inappropriate Capability

High
Confidence
95% confidence
Finding
Resolving employee identities from mobile numbers is a sensitive directory lookup capability that is not inherently required for attendance analytics. In this context it can be used to map phone numbers to employee accounts, enabling privacy violations, targeted surveillance, or unauthorized correlation of personal and HR data.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill invokes environment variables and a remote DingTalk API but declares no explicit tool scope or permission boundaries. That weakens least-privilege controls and makes it easier for an agent/runtime to over-grant access, especially since the skill also instructs shell execution and local persistence.

Vague Triggers

Medium
Confidence
96% confidence
Finding
该描述不仅列出了一些具体关键词,还进一步要求“即使用户没有明确说‘打卡’,只要涉及员工到岗、缺勤、工时相关的问题,也应该使用这个 skill”。这使激活范围扩展到较广泛的人事或管理讨论场景,缺少明确边界或排除条件,容易导致非考勤查询场景也触发该技能。

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill directs remote access to attendance data and automatic local SQLite persistence without clearly surfacing those data-handling behaviors to the user at the point of use. Because attendance records are sensitive employee data, hidden network retrieval and local retention materially increase privacy, compliance, and data-exposure risk.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The code stores attendance-related data in a local SQLite database for up to seven days, and the schema later associates user IDs, names, and exception results across dates. Persisting named attendance exceptions transforms a transient query tool into a local HR activity store, increasing exposure if the host is shared, compromised, or backups are accessed.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script writes attendance history, user IDs, names, and query timestamps to a local SQLite file without an explicit user-facing warning or consent step. Silent persistence of employee attendance exceptions can violate privacy expectations and organizational data-handling requirements, especially for HR-related records.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The file includes functions for department enumeration and department membership listing, which go beyond the described purpose of querying attendance outcomes. Even if not exercised in the current main flow, retaining organization-wide discovery primitives in the skill broadens the attack surface and enables lateral data collection if the skill is extended or reused.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The skill is presented as an attendance query/analysis utility, but it also contains capabilities to resolve a user by mobile number and retrieve detailed user profile information. That expands access to employee identity data beyond the minimally necessary scope for attendance analysis and increases the chance of unnecessary collection or misuse of personal data.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
In main execution mode, the script automatically retrieves tokens, resolves an admin phone number, enumerates attendance-group users, and queries attendance records over the network. While these calls are part of the script's purpose, there is no visible runtime disclosure that employee identifiers and phone-based lookups will be transmitted to external APIs.

Context-Inappropriate Capability

Low
Confidence
91% confidence
Finding
The instruction to run a filesystem-wide find over the user's home directory is broader than necessary for attendance analysis and can enumerate unrelated files and project paths. Even if intended for convenience, it expands access scope and may expose sensitive filesystem structure or discover unintended copies of the script.

Description-Behavior Mismatch

Low
Confidence
79% confidence
Finding
The manifest describes the skill as querying and analyzing DingTalk attendance punch data, which suggests read/query behavior. The file additionally documents automatic persistence of every API query result into a local SQLite database and later reuse of that stored data, which is a broader behavior than the manifest explicitly states.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
“输出风格:简洁、结构化,用中文”属于对输出语言的硬性限定。文件中未说明这是用户自选、可切换选项,亦未给出必须使用中文的合规或区域性依据,因此构成语言/locale 选择上的自然语言政策问题。

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
The department-list function hard-codes the default language as zh_CN, which forces a specific locale unless callers override it. The policy requires offering language or locale choice, or clearly documenting and justifying the restriction.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
This function sets language='zh_CN' by default, which imposes a locale preference in returned user details. There is no evidence in this file of an explicit user choice or a documented region-specific justification.

Static analysis

No suspicious patterns detected.