Back to skill

Security audit

cn-calendar

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its China calendar purpose, but it can persistently rewrite its own executable query code from externally fetched data and gives compliance-sensitive tax deadline guidance with inconsistent source controls.

Review before installing. This skill is reasonable for China holiday/workday lookup using the bundled 2025-2026 data, but avoid relying on its inferred deadline command for tax compliance and require explicit approval before any remote fetch or persistent update. Prefer a version that stores new calendar data as validated data files rather than rewriting Python source.

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/fetch_holidays.py:118
Finding
Unvalidated Input Can Corrupt the Executable Query Script<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch_holidays.py:79-107` and `scripts/fetch_holidays.py:118-141` **Vulnerability Type**: Unsafe self-modification and insufficient input validation **Risk Level**: Medium ### Vulnerable Code ```python def update_workday_script(year: int, holidays: list[str], extra_workdays: list[str]): """将新年份数据插入 workday_query.py""" script_path = SKILL_DIR / "scripts" / "workday_query.py" content = script_path.read_text(encoding="utf-8") # 检查是否已有该年份数据 if f"HOLIDAYS_{year}" in content: print(f"ℹ️ workday_query.py 已包含 {year} 年数据,跳过更新", file=sys.stderr) return new_block = generate_workday_data_block(year, holidays, extra_workdays) # 在 ALL_HOLIDAYS 定义之前插入新数据块 insert_marker = "ALL_HOLIDAYS = " content = content.replace(insert_marker, new_block + "\n" + insert_marker) # 更新 ALL_HOLIDAYS 和 ALL_EXTRA_WORKDAYS 合并集合 content = re.sub( r"ALL_HOLIDAYS = ([^\n]+)", lambda m: m.group(0).rstrip() + f" | HOLIDAYS_{year}", content ) content = re.sub( r"ALL_EXTRA_WORKDAYS = ([^\n]+)", lambda m: m.group(0).rstrip() + f" | WORKDAYS_{year}", content ) script_path.write_text(content, encoding="utf-8") ``` ```python year = int(args[0]) mode = args[1] if len(args) > 1 else "--check" if mode == "--check": result = check_local(year) if result: print(json.dumps({"status": "exists", "year": year, "path": result["path"]})) else: print(json.dumps({"status": "missing", "year": year})) elif mode == "--save": # 此模式由 Claude 在获取到官网数据后调用 # 数据通过 stdin 传入(JSON 格式) data = json.loads(sys.stdin.read()) holidays = data.get("holidays", []) extra_workdays = data.get("extra_workdays", []) md_content = data.get("md_content", "") if md_content: save_references_md(year, md_content) if holidays: update_workday_script(year, hol ...[truncated 2734 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Validate the year before using it** - Require an integer in Python's supported calendar range, such as `1` through `9999`. - Apply a narrower operational range if the Skill only supports modern calendar years. 2. **Validate the complete input schema** - Require `holidays` and `extra_workdays` to be arrays of strings. - Reject unexpected types and malformed JSON. - Parse every value with `date.fromisoformat()`. - Verify that every parsed date belongs to the requested year. - Reject duplicate or conflicting dates appearing in both collections. - Apply reasonable collection-size limits. 3. **Avoid constructing identifiers from untrusted input** - Store data in a dictionary keyed by an integer year rather than generating variable names: ```python HOLIDAYS_BY_YEAR = { 2025: {...}, 2026: {...}, } ``` 4. **Validate generated source before installation** - Generate the complete candidate file in memory. - Parse it with `ast.parse()` and optionally compile it with `py_compile`. - Do not alter the active script if validation fails. 5. **Use atomic replacement** - Write the candidate to a temporary file in the same directory. - Flush and synchronize it as appropriate. - Atomically replace the target with `os.replace()` only after successful validation. - Preserve a backup or implement rollback. 6. **Check update markers** - Confirm that `ALL_HOLIDAYS` and `ALL_EXTRA_WORKDAYS` markers are each found exactly once. - Abort without writing if the expected source structure is absent or ambiguous. 7. **Keep coverage metadata synchronized** - Update `COVERED_YEARS` through the same validated transaction, or derive coverage directly from the year-keyed data structure. 8. **Add regression tests** - Test negative years, years above `9999`, malformed dates, mismatched years, incorrect JSON types, duplicate dates, conflicting holiday/workday entries, abse ...[truncated 51 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (18)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documented behavior promises official-source retrieval and tax-deadline accuracy, but the instructions rely on local scripts, a third-party GitHub source, and contradictory logic that may not actually provide authoritative results. In a tax/calendar skill, this mismatch is security-relevant because users may trust outputs for compliance decisions while the implementation silently falls back to less trustworthy or incomplete data paths.

Intent-Code Divergence

High
Confidence
96% confidence
Finding
The document simultaneously says tax filing deadlines must come from official yearly reference files and also instructs use of a `deadline` command that calculates them. This inconsistency can cause the agent to infer compliance-sensitive deadlines from generic workday logic rather than authoritative tax calendars, leading to incorrect legal or financial guidance.

Lp3

Medium
Category
MCP Least Privilege
Confidence
80% confidence
Finding
The skill instructs file reads and writes but does not declare any explicit tool scope or permissions boundary. That creates an authorization gap where an agent may perform local state changes beyond what users reasonably expect, increasing the chance of unintended modification or abuse if the skill is invoked automatically.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill instructs writing new reference files, modifying source code, and then executing the modified script, but it does not clearly disclose to users that invoking the skill can change persistent local state. Hidden state changes are dangerous because they can permanently alter later behavior, introduce integrity issues, and make a simple informational skill behave like a self-modifying system.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The skill directs use of a broad `exec` capability to run code after modifying local files, even though the stated task is a calendar lookup. Allowing code execution in a content/update workflow expands the attack surface: malformed or adversarially influenced data could lead to execution of changed code, and the capability exceeds what is necessary for answering user queries.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The text states that Beijing 12366 data (`ssjg=111000000`) is used as the national unified standard reference. This imposes a specific regional locale on all users without offering a choice or documenting why this locale is universally appropriate for every query.

External Transmission

Medium
Category
Data Exfiltration
Content
# 接口:POST https://12366.chinatax.gov.cn/bsfw/calendar/getCalendarListForMonth
# 参数:ssjg=111000000(北京市)&bssj=YYYY-MM
# 示例:查询2027年1月
curl -X POST https://12366.chinatax.gov.cn/bsfw/calendar/getCalendarListForMonth \
  -d "ssjg=111000000&bssj=2027-01"
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The entire skill file is written as a Chinese-language reference and does not indicate that language selection is optional or that the skill is intentionally limited to Chinese-speaking users. Under the stated policy, forcing a specific language without user opt-in can be a natural-language policy violation.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The module docstring says this script '从国务院官网抓取指定年份的法定节假日通知,解析后' and its usage examples describe a fetch operation. However, the implementation only checks for local files, reads JSON from stdin, writes a markdown reference file, and edits another local Python file; there is no HTTP client, request logic, or HTML parsing anywhere in the file.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
This script rewrites another Python source file using externally supplied holiday/workday data, effectively turning untrusted input into code edits. Even though the values are expected to be dates, there is no strict schema validation, no transactional safeguards, and no confirmation step, so malformed or adversarial input can corrupt repository code or introduce persistent unsafe behavior in the skill.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
In --save mode, the script accepts JSON from stdin and uses it to write repository files, including markdown content and generated Python data blocks, without authentication, provenance checks, or user confirmation. In this skill context, where an agent may process remotely sourced content, this increases the risk of supply-chain style tampering, persistent data corruption, or poisoning of future query results.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The documentation claims tax filing calendar support from the State Taxation Administration, but the code contains no tax-calendar source data and simply rolls a provided date forward to the next workday. In a tax-deadline use case, this can misstate actual statutory deadlines, extensions, or filing-calendar rules and mislead users into noncompliant actions.

Description-Behavior Mismatch

Medium
Confidence
98% confidence
Finding
The skill metadata promises that out-of-range years are automatically fetched from official sources and persisted, but the implementation only prints a warning and exits. In a calendar/compliance tool, this mismatch can cause users or upstream agents to assume fresh authoritative data exists when it does not, leading to incorrect workday or filing-date decisions.

Missing User Warnings

Low
Confidence
88% confidence
Finding
The skill says it will fetch holiday data from GitHub and, elsewhere, tax calendar data from the 12366 API when local data is unavailable. Although this is part of the workflow, the markdown does not plainly disclose to users that their request may trigger outbound network access to third-party or government services.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
This markdown file is entirely written in Chinese and scoped to mainland China holidays, with no indication that language or locale is optional. Under the natural-language policy rule, forcing a specific language without user opt-in can be a locale/language policy violation.

Intent-Code Divergence

Low
Confidence
95% confidence
Finding
The function docstring states '从本地 references/holidays-YYYY.md 解析出假期数据', suggesting it extracts holiday data from the markdown file. In reality, the implementation explicitly returns only the file path and year, and the inline comment says Claude will read and parse it instead, which contradicts the stated function behavior.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
The module description and command help are entirely in Chinese, and later user-facing output strings are also fixed to Chinese. Under the policy rule, forcing a specific language without opt-in can be a natural-language policy violation unless the locale constraint is explicitly documented and justified as region-specific.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
The weekday labels and all printed status messages are hard-coded in Chinese, so the tool enforces one language at runtime. Because there is no language choice or explicit opt-in, this matches the language/locale policy concern for natural-language content in code.

Static analysis

No suspicious patterns detected.