Grace period edits bypass `skip_review_media_groups` media review

Summary

The “review media” check (skip_review_media_groups site setting) is only enforced
at post creation time, in NewPostManager. Edits go through PostRevisor,
which never runs the media check. A user can therefore post plain text first
(passing review), then add images via an edit — and the post never enters the
review queue.

Worse, if the edit happens within editing_grace_period (default 5 minutes) and
the diff is smaller than editing_grace_period_max_diff (default 100 chars —
a single uploaded-image markdown line is ~40–60 chars), the edit creates no
revision and no pencil icon
, so the bypass is completely invisible in the UI.

Steps to reproduce

  1. Configure skip_review_media_groups so that regular users (e.g. TL0/TL1) are
    not exempt — posts with media should require approval.
  2. As a regular user, create a post containing only text. It is approved/posted
    normally (no media → no review).
  3. Within the grace period, edit the post and insert an uploaded image.

Expected

The post (now containing media) should be sent to the review queue, or at least
the edit should be subject to the same media check as post creation.

Actual

  • The post is published with the image and never enters the review queue.
  • No revision record is created, no edit indicator is shown.

Evidence (production instance)

p.version                                   # => 1
PostRevision.where(post_id: p.id).count     # => 0
p.created_at                                # => 2026-07-30 07:33:28 UTC
p.updated_at                                # => 2026-07-30 07:34:00 UTC
UploadReference.where(target: p).pluck(:created_at)
                                            # => [2026-07-30 07:34:01 UTC]

Text-only post created at 07:33:28, image added by an edit ~32 seconds later —
no visible edit history, no review.

Relevant code

  • lib/new_post_manager.rb — post_needs_approval? returns :contains_media
    via contains_embedded_media?, but this only runs for new posts.
  • app/models/post_analyzer.rb#embedded_media_count — the media counting logic.
  • PostRevisor — no equivalent media check on edit.

Suggested fix

Run the contains_media check in PostRevisor as well (when the edit
introduces media and the editor is not in skip_review_media_groups / not
staff), enqueueing a ReviewablePost for the edited post.

2 Likes

Thanks for the report @Editor0732 :+1: Will be fixed by

I tried deploying this PR and noticed an asymmetry in the media moderation mechanisms between new posts and editors, and I’d like to raise this issue:

New posts with media — ReviewableQueuedPost (review before publish)

  • The post is not created at all; the content sits in the reviewable payload until approved
  • The author sees the “awaiting approval” section (pending_posts) on the topic page
  • The post only becomes visible to everyone after a moderator approves it (perform_approve_postPostCreator)
  • On rejection, the content is discarded — it was never public

Edits that add media — ReviewablePost (publish first, review after)

  • The edit takes effect immediately; the new version (including the image) is instantly visible to everyone
  • There is no “under review” notice for the author — and for grace-period edits there isn’t even a revision, so the original content leaves no trace in the UI
  • On rejection, the post is deleted (perform_reject_and_delete), recoverable via the previous revision

The concern

With the current approach, the problematic image becomes publicly visible before any moderator can act, potentially for a long time depending on review turnaround. That seems to weaken the whole point of skip_review_media_groups — the setting’s description says posts containing media are “sent to staff for review”, which reads like they shouldn’t be public in the meantime.

Possible improvement

  1. Queue the edited content instead of applying it.(I think better) When an edit introduces new media, keep the post unchanged, notify the author that the new edit is pending review, and only apply the edited content to the post once a moderator approves it — discard it on rejection. This mirrors the new-post behavior as closely as possible. (Implementation-wise, this would need a reviewable variant whose approval performs a revise on the existing post rather than creating a new one.)

  2. Hide the post when an edit introduces new media, so only the author sees it with an “awaiting approval” notice, and use the existing perform_approve_and_unhide action on approval — the ReviewablePost actions already support this.