T09 · Insecure Skill Coding Practices
- Location
scripts/cal.py:408- Finding
Calendar mutation commands do not enforce confirmation and UID deletion bypasses calendar protections
- Content
View full analysis
Vulnerability Details
File Location:
scripts/cal.py:408-416, 433-478; documented security requirement inSKILL.md:119-131
Vulnerability Type: Missing authorization gate and inconsistent deletion scope enforcement
Risk Level: MediumTechnical Analysis
SKILL.mdrequires the agent to display complete event details and obtain user confirmation before writing or deleting calendar events. However, the executable entry point does not require a confirmation token, interactive approval, or other verifiable proof of consent.For event creation,
--dry-runis optional. If it is omitted, the command immediately authenticates to iCloud and performs CalDAVPUTrequests:python if args.get("dry_run"): print("dry-run:将写入 %d 条到「%s」:" % (len(todo), cal_name)) for uid, _lines, e in todo: print(" %s %s-%s %s%s" % (e["date"], e["start"], e["end"], e["title"], " @%s" % e["location"] if e.get("location") else "")) return cli, home, calendars = connect(prof) target = get_calendar(prof, cli, home, calendars, cal_name) ok = 0 for uid, lines, e in todo: url = target.rstrip("/") + "/" + urllib.parse.quote(uid, safe="") + ".ics" s, body = cli.dav("PUT", url, calendar_body(lines), ctype="text/calendar; charset=utf-8") if s not in (200, 201, 204): die("写入失败 %s(%d)" % (uid, s), body.decode("utf-8", "replace")[:300])The UID-based cancellation path is broader than the date-based cancellation path. It searches every calendar and deletes a matching resource without requiring the UID to use the
calpal-prefix, without restricting the operation to the configured plans calendar, and without applying the commitments-calendar protection:python if args.get("uid"): # 按 UID 精确删:扫全部日历找到那条资源的 URL for name, url in calendars.items(): s, c = cli.dav("PROPFIND", url, '<?xml version="1.0" encoding="UTF-8"?>' '<d:propfind xmlns:d="DAV:"><d:prop><d: ...[truncated 3361 chars]- Remediation
View remediation
Remediation Suggestions
- Require a machine-verifiable confirmation artifact for every non-dry-run mutation. For example, generate a short-lived confirmation token from the normalized operation details during preview and require that token for
PUTorDELETE. - Make preview the default behavior. Require an explicit mutation option such as
--apply --confirmation-token <token>before contacting CalDAV with a state-changing method. - Restrict
cancel --uidto UIDs beginning withcalpal-and to the configured plans calendar by default. - If deletion of foreign or commitments-calendar events is genuinely required, place it behind a separate explicit mode with a fresh confirmation tied to the exact calendar, UID, title, date, and time.
- Apply the same calendar and ownership checks to UID-based and date-based deletion paths through a shared authorization function.
- Validate the response status from every
DELETErequest and report failure rather than printing a successful deletion unconditionally. - Add regression tests proving that:
- mutation fails without a valid confirmation token;
- foreign UIDs cannot be deleted through the normal cancellation command;
- the commitments calendar remains protected in both date- and UID-based paths;
- expired or operation-mismatched confirmation tokens are rejected.
- Require a machine-verifiable confirmation artifact for every non-dry-run mutation. For example, generate a short-lived confirmation token from the normalized operation details during preview and require that token for
