T09 · Insecure Skill Coding Practices
- Location
scripts/work_schedule.py:175- Finding
Persistent Markdown Injection Through Unescaped Schedule Data
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is a disclosed local work-schedule ledger with attachment archiving and optional daily reminders, with manageable privacy and rendering risks but no evidence of malicious behavior.
Install only if you want work messages, notes, history, and selected attachments stored persistently on this machine. Review cron setup before approving daily reminders, avoid saving secrets or highly sensitive documents, and be cautious with links or Markdown content added from untrusted messages.
scripts/work_schedule.py:175Persistent Markdown Injection Through Unescaped Schedule Data
scripts/work_schedule.py:53Schedule and Attachment Data May Be Created With Permissive Filesystem Permissions
The skill description understates or omits important operational behavior, notably setup of recurring reminders via cron/OpenClaw scheduled tasks. Undeclared persistence or scheduling capabilities are security-relevant because they let the skill establish ongoing execution beyond a single user request, which can surprise users and operators and expand blast radius if misused.
The skill invokes shell, file, environment, and network-capable behavior but does not declare any explicit tool scope or permission boundaries. That makes the effective privilege surface ambiguous and increases the risk of overbroad access, especially because the skill processes user-supplied content into filesystem writes and attachment handling.
The trigger rules are broad enough to capture ordinary conversational scheduling language, including messages without explicit prefixes. This can cause unintended persistence of user content, accidental collection of sensitive work details, and unnecessary invocation of file-writing and attachment-related actions when the user's intent was ambiguous.
subprocess module calls execute external commands. Without careful input validation, this enables command injection.
if args.dry_run:
print(json.dumps(command, ensure_ascii=False, indent=2))
return
result = subprocess.run(command, text=True, capture_output=True, check=False)
if result.stdout:
print(result.stdout, end="")
if result.stderr:
The file sets a default timezone of "Asia/Shanghai" and uses Chinese-only user-facing output and error text, such as the timezone validation error. This imposes a specific locale/language behavior on all users without offering a choice or documenting that the tool is region-specific.
The argument validation errors are hard-coded in Chinese ("时间必须为 HH:MM", "时间超出范围") and the script also uses a Chinese default reminder name. This imposes a specific language on users with no opt-in or documented locale constraint, which matches the language/locale policy violation category.
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.
"category": normalize_text(args.category) if args.category is not None else None,
"notes": normalize_text(args.notes) if args.notes is not None else None,
}
provided = {key: value for key, value in changes.items() if getattr(args, key) is not None}
if not provided:
raise SystemExit("没有提供需要修改的字段")
if args.priority is not None and args.priority not in PRIORITY_ORDER: