fix(flows): redact customer text from reply_received event payload

The `reply_received` event was persisting `text: message.text` verbatim
into flow_run_events.payload. A customer prompted "what's your card
number?" by a collect_input node would leave the PAN sitting in the
events table forever, surfaced via the runs viewer to anyone with
access.

Switch to `text_length` only. The `node_entered` event already records
`captured_length` for the same reason after a successful capture; this
makes the asymmetry symmetric.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Arnas Donauskas 2026-05-22 15:35:42 +03:00
parent 9ff4a8d1ba
commit 8ac764e3b8
No known key found for this signature in database

View File

@ -822,11 +822,18 @@ async function handleReplyForActiveRun(
run: FlowRunRow, run: FlowRunRow,
message: ParsedInbound, message: ParsedInbound,
): Promise<DispatchInboundResult> { ): Promise<DispatchInboundResult> {
// Note: we intentionally do NOT persist the raw customer text. A
// `collect_input` prompt that asks "what's your card number?" would
// otherwise leave the PAN sitting in flow_run_events.payload forever,
// visible to anyone with access to the runs viewer or the events
// table. Length is enough for "did they actually reply?" debugging;
// for the captured value itself, the `node_entered` event already
// records `captured_key` + `captured_length` after the var is stored.
await logEvent(db, run.id, "reply_received", run.current_node_key, { await logEvent(db, run.id, "reply_received", run.current_node_key, {
meta_message_id: message.meta_message_id, meta_message_id: message.meta_message_id,
reply_kind: message.kind, reply_kind: message.kind,
reply_id: message.kind === "interactive_reply" ? message.reply_id : null, reply_id: message.kind === "interactive_reply" ? message.reply_id : null,
text: message.kind === "text" ? message.text : null, text_length: message.kind === "text" ? message.text.length : null,
}); });
if (!run.current_node_key) { if (!run.current_node_key) {