discourse/lib/validators
Rafael dos Santos Silva ad459f7806
FIX: Cap the number of [quote] tags allowed per post (#40281)
## Summary

Reports have surfaced of posts that lock up or crash browsers when their
topic loads, even though the raw is well within `max_post_length`. The
trigger is many `[quote=...]` BBCode openers per post — typically
unbalanced with the matching `[/quote]` closers. When the BBCode block
rule can't pair them up, each opener falls through to inline parsing and
cooks into its own `<p>[quote=...]</p>` paragraph. Posts with hundreds
to thousands of these paragraphs are cheap to author but expensive to
render: thousands of DOM nodes, per-post decoration passes (quote-back
links, MutationObservers, oneboxer, etc.) running once per fragment, and
post-level event handlers all compound.

Examples in the wild have raws of 11–47 KB containing 220–880 `[quote=`
openers, cooking into 25–100 KB of near-identical paragraphs. None of
these come close to `max_post_length`, so the existing length validator
never fires.

This adds a `max_quotes_per_post` site setting (default `50`, set to `0`
to disable). `PostValidator` rejects any post whose raw contains more
`[quote=` / `[quote]` openers than the limit.

## Notes

- The default of 50 is well above any realistic legitimate use (deeply
nested quote-replies in practice top out around 5–10 levels). The four
observed offender posts contain 220, 220, 660, and 880 `[quote=` openers
— all rejected at the default.
- Counts openers only (`[quote=` and `[quote]`, case-insensitive), not
balanced pairs. The DoS comes from openers; closers are cheap.
- Existing offending posts on affected sites still need to be
deleted/rebaked manually — this only stops new ones.

## Test plan

- [x] `bin/rspec spec/lib/validators/post_validator_spec.rb` — all 53
examples pass, including 6 new cases covering: over-limit, at-limit,
unbalanced openers, plain `[quote]`, case-insensitivity, and
disable-via-zero.
- [ ] Manually try to submit a post with 51+ `[quote=...]` lines via the
composer and confirm the error message.
- [ ] Try the same via the API.
- [ ] Confirm legitimate "Quote Reply" workflows (a handful of nested
quotes) still work.
2026-05-26 10:33:21 -03:00
..
allow_user_locale_enabled_validator.rb
allowed_iframes_validator.rb DEV: Replace Ruby numbered parameters by it where applicable (#37810) 2026-02-13 13:59:07 +01:00
allowed_ip_address_validator.rb
alternative_reply_by_email_addresses_validator.rb
at_least_one_group_validator.rb
categories_topics_validator.rb
category_search_priority_weights_validator.rb
censored_words_validator.rb
color_list_validator.rb
content_localization_locales_validator.rb FEATURE: Add a hidden setting to limit number of content localization locales (#33378) 2025-06-30 15:29:58 +08:00
csp_script_src_validator.rb DEV: Replace Ruby numbered parameters by it where applicable (#37810) 2026-02-13 13:59:07 +01:00
css_color_validator.rb
css_color_with_blank_validator.rb UX: add welcome banner text color setting (#34657) 2025-09-24 15:19:40 +08:00
datetime_setting_validator.rb DEV: Add datetime type for site settings / object settings (#36849) 2025-12-30 10:52:30 -06:00
default_composer_category_validator.rb
delete_rejected_email_after_days_validator.rb
email_address_validator.rb FIX: Validate email length (#34786) 2025-09-11 18:58:07 +03:00
email_setting_validator.rb
email_validator.rb
enable_discourse_id_validator.rb FEATURE: log errors when enabling discourse id (#36110) 2025-11-25 11:20:32 +01:00
enable_local_logins_via_email_validator.rb
enable_private_email_messages_validator.rb
enable_sso_validator.rb
external_system_avatars_validator.rb
form_template_yaml_validator.rb DEV: Enable Style/RedundantBegin rubocop rule (#40096) 2026-05-19 18:44:54 +02:00
google_oauth2_hd_groups_validator.rb
group_setting_validator.rb
host_list_setting_validator.rb
integer_setting_validator.rb DEV: Enable Style/RedundantParentheses rubocop rule (#40095) 2026-05-19 15:48:09 +02:00
ip_address_format_validator.rb
language_switcher_setting_validator.rb FEATURE: Also allow language switcher to be shown when users are logged in (#34578) 2025-08-27 23:01:07 +08:00
linkedin_oidc_credentials_validator.rb
markdown_linkify_tlds_validator.rb
markdown_typographer_quotation_marks_validator.rb
max_emojis_validator.rb
max_username_length_validator.rb FIX: Improve group name validation (#31315) 2025-02-19 19:33:46 +02:00
mediaconvert_output_subdirectory_validator.rb DEV: Update mediaconvert to use a subdirectory for output (#36049) 2025-11-20 14:03:14 -07:00
min_username_length_validator.rb FIX: Improve group name validation (#31315) 2025-02-19 19:33:46 +02:00
not_username_validator.rb
objects_setting_validator.rb FIX: Fix ObjectsSettingValidator error message handling (#38336) 2026-03-09 14:50:17 -03:00
password_validator.rb
pop3_polling_enabled_setting_validator.rb DEV: Fix assigned but unused variable Prism warnings (#39436) 2026-04-22 12:42:14 +02:00
post_validator.rb FIX: Cap the number of [quote] tags allowed per post (#40281) 2026-05-26 10:33:21 -03:00
quality_title_validator.rb
regex_presence_validator.rb
regex_setting_validation.rb
regex_setting_validator.rb
regexp_list_validator.rb DEV: Enable Style/RedundantBegin rubocop rule (#40096) 2026-05-19 18:44:54 +02:00
reply_by_email_address_validator.rb
reply_by_email_enabled_validator.rb
search_ranking_weights_validator.rb
search_tokenize_chinese_validator.rb
search_tokenize_japanese_validator.rb
selectable_avatars_mode_validator.rb
sso_overrides_email_validator.rb
string_setting_validator.rb DEV: Enable Style/RedundantParentheses rubocop rule (#40095) 2026-05-19 15:48:09 +02:00
stripped_length_validator.rb SECURITY: Respect max length in bot-human PMs 2025-06-09 12:04:11 +08:00
timezone_validator.rb
topic_setting_validator.rb FEATURE: Add new configurable moderation guide (#36287) 2025-12-01 10:30:32 +08:00
topic_title_length_validator.rb
unicode_username_allowlist_validator.rb
unicode_username_validator.rb DEV: Deprecate external_system_avatars_enabled (#33436) 2025-07-04 16:02:04 +08:00
unique_among_validator.rb DEV: Hand-pick Rails/WhereNot autofixes (#35117) 2025-10-03 13:29:22 +02:00
upload_setting_validator.rb DEV: clean up splash SVG on upload, not when rendering (#37681) 2026-02-16 13:14:35 +10:00
upload_validator.rb DEV: Enable Style/RedundantParentheses rubocop rule (#40095) 2026-05-19 15:48:09 +02:00
url_validator.rb
user_full_name_validator.rb
user_password_validator.rb
username_setting_validator.rb
video_conversion_enabled_validator.rb FEATURE: Add support for aws MediaConvert (#33092) 2025-07-23 11:58:33 -06:00
watched_words_validator.rb