T01 · Skill Instruction Hijacking
- Location
scripts/check_upcoming.py:24- Finding
Stored Indirect Prompt Injection Through Schedule Reminder Content
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is a real shared schedule tool, but it sets up recurring background agents and external reminders in ways that need review before use.
Install only if you are comfortable with a shared team calendar whose entries can be emailed and sent through DingTalk by recurring background jobs. Before production use, restrict who can add/update/delete schedules, store SMTP credentials outside the tracked project config, escape schedule fields in HTML email, and ensure cron reminder agents cannot treat schedule text as instructions.
scripts/check_upcoming.py:24Stored Indirect Prompt Injection Through Schedule Reminder Content
scripts/email_summary.py:69Unescaped User-Controlled Fields in HTML Email Summaries
scripts/config.json:2SMTP Authorization Credential Designed to Be Stored in a Plaintext Project Configuration File
代码整体仍属于日程管理/提醒相关领域,并使用了本地 schedule_manager 模块,因此与声明的核心场景部分一致。但存在两处明显不符:第一,声明提到提醒渠道是“钉钉提醒”,而代码注释和输出用途明确是由 cron 调用并通过 QQ Bot 通道推送,这是未声明且与已声明渠道不一致的能力。第二,声明特别说明“所有日程操作通过 schedule_manager.py 完成”,但该代码块是独立脚本 check_upcoming.py,负责定时查询、格式化提醒、标记已提醒并输出结果,说明实际还存在 schedule_manager.py 之外的日程操作流程。故应判定为描述与行为存在实质性不匹配。
描述与代码的核心目的大体一致:它确实是一个本地日程管理模块,使用 Python 和 SQLite 管理日程,支持增删改查与冲突检测。代码还实现了替代时间建议、未来日程查询、即将提醒查询和提醒状态标记,均属于日程系统合理范围。但描述中明确声称支持“邮件汇总、钉钉提醒”,而提供的代码片段完全没有邮件相关实现,也没有任何钉钉集成或外部通知发送能力,只是查询哪些日程即将到期以及标记 remind_sent 状态。因此描述对能力有实质性夸大,属于描述与实际行为不完全一致,应判定为 mismatch。
The README explicitly describes a team-shared calendar plus hourly email summaries and DingTalk reminders, but it does not disclose the privacy and access-control implications to users. In this context, members may assume personal scheduling data is private when in fact all participants can view or alter shared entries and sensitive meeting details may be redistributed through email and chat notifications.
The deletion examples instruct users to cancel or delete schedules without warning that the system uses a single shared database for the whole team. In a shared-calendar skill, this creates a real integrity risk because a user may unintentionally remove events relied on by others, causing disruption or loss of important scheduling data.
The skill instructs the agent to read local configuration and operate local scripts/SQLite data, but it declares no explicit tool scope or allowed-tools boundary. In practice this increases the chance that the agent can access broader local files than intended, especially because the skill also references cron state under ~/.openclaw/cron/jobs.json and multiple script paths.
The trigger terms are broad and overlap with common conversation topics like schedules, reminders, meetings, and trips. In this skill, accidental invocation is more dangerous because the skill can modify shared persistent team data and register autonomous cron jobs, so a casual message could lead to unintended reads, writes, or reminder setup.
The skill manages a team-shared SQLite schedule and supports create/update/delete operations plus persistent reminders, but it does not clearly warn users that actions affect shared data visible to others. In group/team contexts this can cause unauthorized or accidental modification of other users' schedules, privacy leakage, and surprise persistence across sessions.
The technical document expands the skill from a local schedule manager into a multi-module system with background tasks and external integrations. That scope mismatch matters because operators and users may grant trust based on the manifest's 'local' framing while the implementation is documented to perform broader actions, increasing the chance of unnoticed data handling and unintended capability exposure.
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Agent 在启动时会扫描所有 Skill,当用户的请求匹配某个 Skill 时,Agent 会读取该 SKILL.md 并按照其中的指引操作。
本系统的 Skill 文件是 `skills/schedule-manager/SKILL.md`,其中定义了:
- 可用的 Python 命令及参数格式
- 添加/修改/删除/查询日程的操作步骤
- 模糊指令的解析策略
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Agent 在启动时会扫描所有 Skill,当用户的请求匹配某个 Skill 时,Agent 会读取该 SKILL.md 并按照其中的指引操作。
本系统的 Skill 文件是 `skills/schedule-manager/SKILL.md`,其中定义了:
- 可用的 Python 命令及参数格式
- 添加/修改/删除/查询日程的操作步骤
- 模糊指令的解析策略
Direct SMTP use with stored credentials introduces an external exfiltration channel for schedule contents, which is broader than the stated local-management purpose. In this skill context, schedules may contain sensitive meeting names, times, locations, and notes, so automatic email delivery materially increases confidentiality risk if enabled without strict disclosure and controls.
The document states that Python scripts only perform data operations and do not handle messaging, yet elsewhere describes modules that send email over SMTP. This inconsistency can mislead reviewers about the trust boundary and conceal data egress paths, making security review and informed consent weaker.
The document describes automatic email summaries and proactive DingTalk reminders that transmit schedule data to external channels, but does not clearly state that user data will be sent out on a timer. This is dangerous because users may reasonably expect a local scheduling tool, while the documented behavior creates silent recurring disclosure of potentially sensitive calendar information.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
CREATE TABLE schedules (
id INTEGER PRIMARY KEY AUTOINCREMENT, -- 自增主键
title TEXT NOT NULL, -- 日程标题
description TEXT DEFAULT '', -- 日程描述
清单将该技能描述为本地日程管理,且提醒能力明确写为“邮件汇总、钉钉提醒”。但该脚本模块文档说明它由定时任务调用并通过 QQ Bot 通道推送提醒,表明实际行为包含另一种未声明的提醒渠道。这个差异属于技能描述与实际实现能力不一致。
模块注释明确表示脚本“通过 QQ Bot 通道推送”,给人的意图是该脚本自身执行消息发送操作。实际代码只查询数据库、标记 reminded,并将结果以 JSON 打印到标准输出,没有任何 QQ API、机器人 SDK 或消息发送逻辑,因此文档与代码行为直接背离。
The script emits full schedule reminder content, including titles, times, locations, and descriptions, to stdout in JSON. In a cron/bot pipeline, stdout is often captured by logs, supervisors, or downstream integrations, which can expose sensitive calendar data to unintended readers; the local team-scheduling context makes this more concerning because meeting metadata may contain confidential business information.
This code sends upcoming schedule details by email via SMTP, which transmits potentially sensitive personal calendar data to an external mail server. While the module docstring mentions hourly sending, the operational code provides no confirmation prompt or runtime user-facing disclosure before transmitting the data.
This Python file contains natural-language documentation and CLI output exclusively in Chinese, including the module docstring and later user-facing error/help text. Because the skill does not offer an opt-in or alternative locale, it enforces a specific language policy on all users.
The delete_schedule function permanently removes schedule records from the SQLite database, but there is no confirmation prompt, visible user-facing warning, or explanatory comment indicating that this action is destructive. In this file, the CLI exposes the delete command directly, so users may trigger irreversible data loss without any disclosure.
L005 及全文均以中文直接规定技能描述和交互方式,但没有说明该技能仅面向特定中文环境用户,也未提供语言选择。按语言/区域政策,若强制特定语言而无用户选择或明确、合理的地域限定,属于自然语言策略问题。
SQP-3 适用于所有文件,需检查自然语言层面的语言/地区政策问题。该文档从标题到所有用户交互示例均默认并固定为中文,未说明是否支持其他语言、是否仅面向特定中文用户群体,或是否允许用户自主选择语言,因此存在潜在的语言策略不透明问题。
The docstrings and reminder strings are exclusively in Chinese, and the file does not state that the skill is intended only for Chinese-speaking users or offer any language selection. This can violate language/locale policy when a skill forces one language without user opt-in or documented justification.
The config sets the timezone to "Asia/Shanghai", which imposes a specific locale setting in a natural-language-adjacent configuration value. Under the policy, locale constraints should either be user-selectable or clearly justified as region-specific; neither is evident in this file.
The login step uses a configured password to authenticate to the SMTP server, which is sensitive credential material. The file contains no warning, comment, or user-facing disclosure about credential use or the need to protect the configuration containing these secrets.