Skip to content

feat(telegram): mark forwarded-message provenance in inbound content #686

Description

@griffinwork40

Problem

When a user forwards a message to the bot, the forwarded content flows into the model as if the user typed it — a forwarded text lands in msg.text (so bot.on('text') fires) and a forwarded photo hits bot.on('photo') — but the provenance is stripped. There is zero handling of forward metadata in production: no forward_origin / forward_from / forward_from_chat / forward_sender_name / is_automatic_forward references anywhere in non-test src/.

Consequence: the model cannot distinguish "the user asserts X" from "the user is relaying X from elsewhere." Since #685 established sender-attribution markers as a prompt-injection-posture control, unmarked forwarded third-party content is an even stronger case for a trust marker — forwarded text is untrusted content presented as the operator's own words.

Proposal

When message.forward_origin is present (Bot API 7.0+; also handle the legacy forward_from / forward_from_chat / forward_sender_name), prepend a system-trusted, sanitized marker such as [forwarded from <origin>], where <origin> is the forwarding source: a user's name, a channel/chat title, or a "hidden user" (for MessageOriginHiddenUser).

  • Reuse the sanitization pattern in src/telegram/sender-attribution.ts (sanitizeField) so the origin cannot forge or break out of the marker.
  • Treat forwarded content as untrusted — the marker is the model's signal to weigh it as relayed material.

Additionally, detect is_automatic_forward (a channel post auto-forwarded into its linked discussion group) so the bot can avoid double-processing (ties into the group-chat work).

Evidence

  • Model input is senderPrefix(...) + msg.text with no forward handling — src/telegram/handlers/message.ts:510,529.
  • Zero forward-field references in non-test src/ (verified by repo-wide grep).
  • Inbound handlers are text + photo only — src/telegram/bot.ts:283,288.

Source: internal Telegram group/channel audit, rec F2. Sibling of the reply-context fix (F1, PR incoming) and the inbound-media ingestion gap (F3).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions