T01 · Skill Instruction Hijacking
- Location
scripts/openclaw_cron_builder.py:49- Finding
Stored Prompt Injection in Scheduled Agent Messages
- Content
View full analysis
Vulnerability Details
File Location:
scripts/config_manager.py:363,399;scripts/openclaw_cron_builder.py:49-64,100-106
Vulnerability Type: Stored prompt injection through an untrusted search keyword
Risk Level: MediumVulnerable Code
scripts/config_manager.py:363accepts the keyword as unrestricted text:python parser.add_argument("--keyword", "-k", type=str, help="搜索关键词")scripts/config_manager.py:397-404persists the value:python if args.save: config = save_config( keyword=args.keyword, max_results=args.max, sort=args.sort, timezone=args.timezone, )scripts/openclaw_cron_builder.py:49-64directly interpolates that value into an agent instruction:python def build_analysis_message(config: Dict[str, Any]) -> str: keyword = config.get("keyword") max_results = config.get("max_results") sort = config.get("sort") timezone = config.get("timezone") or DEFAULT_TIMEZONE if not keyword: raise ValueError("当前配置缺少 keyword,无法构造任务消息") return ( "请使用当前技能的已保存配置执行一次完整 arXiv 监控流程。" f"检索关键词是 {keyword}。" f"返回数量是 {max_results}。" f"排序方式是 {sort}。" f"时区按 {timezone} 处理。" "请先搜索最新论文,再基于标题和摘要逐篇分析,最后输出完整结构化报告。" "报告必须包含论文列表、每篇论文的关注热点、创新性评估、热点研究方向 Top 10,以及 3 到 5 条趋势判断。" )scripts/openclaw_cron_builder.py:100-106places the generated string in anagentTurnpayload:python payload: Dict[str, Any] = { "name": job_name or derive_job_name(config["keyword"]), "schedule": schedule, "sessionTarget": session_target, "payload": { "kind": "agentTurn", "message": build_analysis_message(config), }, }Technical Analysis
The search keyword is treated both as data and as part of the natural-language instruction sent to a future agent invocation. No allowlist, escapi ...[truncated 1787 chars]
- Remediation
View remediation
Remediation Suggestions
- Pass the search query as a typed data field separate from the agent's instruction text whenever the OpenClaw payload format permits it.
- If a text-only payload is required, serialize the keyword using a defined encoding such as JSON and place it inside an explicit untrusted-data boundary.
- Add an instruction stating that content inside the query field is data only and must never be interpreted as an instruction. This should supplement, not replace, structural separation.
- Validate keywords against the intended arXiv query grammar and reject control characters, excessive lengths, and unsupported syntax.
- Require explicit review or confirmation of the final generated agent message before creating a recurring task.
- Restrict permissions on
config.jsonso untrusted local users or processes cannot replace the stored query. - Add tests using instruction-like keywords to verify that they remain inert search data.
