-- 20260502185500_backfill_resanitize_share_cards.sql
--
-- Backfill: NULL out answer_html for share_cards rows older than 1 hour.
--
-- Context: the original sanitize_share_html function was a denylist that
-- comment-wrapped dangerous tags (<!--script>...-->) and renamed on*=
-- attributes to data-x-on*=. A real attacker probed /api/share with
-- <script>, <iframe>, <img onerror>, javascript:, and a <form> payload.
-- Nothing executed, but the comment-wrapping is fragile to a literal
-- "-->" inside an attacker-supplied attribute value, and the renamed
-- attrs left attack indicators visible in served HTML.
--
-- The replacement is a runtime-level allowlist sanitizer (el_html_sanitize)
-- that drops any tag/attribute not on the explicit list. Existing rows
-- that were sanitized by the OLD denylist may carry residual artefacts
-- ("<!--script>alert(1)/script-->" sitting inside answer_html). Rather
-- than rewriting the column row-by-row, we null out answer_html for
-- everything older than 1 hour. The /share/<id> and /said gallery
-- handlers both fall back to the plaintext answer column when answer_html
-- is null, so the user-visible regression is "old shares lose markdown
-- formatting" — not "old shares disappear".
--
-- Anything created in the last hour is post-deploy or pre-deploy testing
-- and is left intact for inspection.
--
-- Applied out-of-band via the Supabase Management API
-- (POST /v1/projects/<ref>/database/query). This file lands the change
-- in version control as the canonical record.

update public.share_cards
   set answer_html = null
 where answer_html is not null
   and created_at < now() - interval '1 hour';
