T09 · Insecure Skill Coding Practices
- Location
scripts/watcher.py:314- Finding
Aggregate delivery bypasses the prompt-injection safety preamble
- Content
View full analysis
str: if not template: return f"Aggregated {len(events)} events. Last: {events[-1].get('event_id')}" out = template out = out.replace("{{count}}", str(len(events))) out = out.replace("{{first_event_id}}", str(events[0].get("event_id"))) out = out.replace("{{last_event_id}}", str(events[-1].get("event_id"))) out = out.replace("{{last_payload}}", str(events[-1].get("payload"))) return out def flush_aggregate(w, state, metrics, state_path: str): agg = w.get("aggregate", {}) window = int(agg.get("window_seconds", 0)) if window <= 0: return name = w.get("name") store = state.setdefault("aggregates", {}) entry = store.get(name) if not entry: return now = time.time() if now - entry.get("window_start", now) < window: return events = entry.get("events", []) if not events: return wake = w.get("wake", {}) session_key = wake.get("session_key") or OPENCLAW_SESSION_KEY if not session_key: return message = render_aggregate_template(agg.get("message_template", ""), events) timeout = int(w.get("ack_timeout_seconds", 30)) ok = send_to_openclaw(session_key, message, timeout) ``` Regular event processing applies a safety preamble, but the aggregate path does not: ```python message = render_template(resolve_message_template(wake), event) if wake.get("add_source_preamble", True): message = build_source_preamble(event) + message ``` ### Technical Analysis The aggregate renderer directly replaces `{{last_payload}}` with the string representation of event-controlled content. The resulting message is passed to `openclaw a ...[truncated 1739 chars]- Remediation
View remediation
