Anti-spam measures for discussion forum

Anti-spam measures for discussion forum

Problem

Discussion forums on Open edX do not have checks against automated or malicious content posting. This weakness was exposed in an incident on a large Open edX instance where spammers used the forum content creation API to spread financial scams that targeted learners.

  • Over several weeks, attackers generated up to 200 posts per hour by calling the API directly.

  • They created usernames that combined instructor names with words such as “admin,” “moderator,” or “staff.” This made their messages look legitimate and increased the chance that learners would trust them.

  • Attackers also replied immediately to new discussion threads. They took advantage of the default setting that sends notifications for new responses to post authors by email and in the notification tray.

  • These replies promoted a WhatsApp group used for fraudulent financial offers.

Initial Response

The platform team took several corrective steps.

  • They searched for the spam accounts using forum activity logs and disabled them, but dozens of new accounts were created every day.

  • They stopped content containing Whatsapp links from being visible on forums. But attackers quickly switched to using URL shorteners, links to Google Docs and GitHub pages, or QR codes embedded in images.

  • The team tried deleting spam content, but the volume quickly became too high to manage manually.

These efforts made it clear that corrective action alone would not work. The system needed both preventive and corrective controls that could stop spam from being created or discourage the attackers.

Potential solutions

Following preventive and corrective measures/features were built:

1. Prevent harmful content from being viewed

  • A configurable feature was added that replaces content containing certain strings with a custom message.

  • The list of strings and replacement text can be set in Django settings.

  • This does not block spam creation but hides harmful content from learners.

Configuration steps

  1. Add a list of URLs, keywords, or regex patterns to the Django setting DISCUSSION_SPAM_URLS.

    1. Regular expressions are supported.

    2. Each pattern matching part of a forum post will be removed or replaced (see below).

    3. DISCUSSION_SPAM_URLS = [ r"https?://chat\.whatsapp\.com/[A-Za-z0-9]+", r"https?://bit\.ly/[A-Za-z0-9]+", ]
  2. Define the replacement text in the Django setting CONTENT_FOR_SPAM_POSTS.

    1. If this value is set, the entire content will be replaced by this value. .

    2. If this value is left blank, only the matched portion (URL or text) will be removed, leaving the rest of the post unchanged.

    3. CONTENT_FOR_SPAM_POSTS = "[removed: suspected spam link]"

Pull requests

  1. https://github.com/openedx/edx-platform/pull/37007

  2. https://github.com/openedx/edx-platform/pull/37009

2. reCAPTCHA v3 on content creation

  • reCAPTCHA was added to the forum content creation API to prevent automated posting.

  • It does not apply to users who have a course or forum role, or whose accounts are more than one month old.

Configuration steps

  1. To enable reCAPTCHA v3, configure the following in django LMS settings (link to code):

    1. RECAPTCHA_PROJECT_ID

    2. RECAPTCHA_PRIVATE_KEY

    3. RECAPTCHA_SITE_KEYS = { 'web': '', 'ios': '', 'android': '', }

  2. Then enable the waffle flag flag discussion.enable_captcha.

Pull requests

  1. https://github.com/openedx/edx-platform/pull/37015

  2. https://github.com/openedx/frontend-app-discussions/pull/785

  3. https://github.com/openedx/edx-platform/pull/37042

  4. https://github.com/openedx/frontend-app-discussions/pull/803

3. Rate limit on content creation

  • A rate limit was added to the content creation API.

  • Users with any course or forum role are exempt from this limit.

Configuration steps

  1. Configure rate limit using django setting DISCUSSION_RATELIMIT (default = '100/m')

  2. Configure the age of learner account beyond which rate limit is not applied in django setting SKIP_RATE_LIMIT_ON_ACCOUNT_AFTER_DAYS (default = 0)

  3. Enable waffle flag discussions.enable_rate_limit.

Pull requests

  1. https://github.com/openedx/edx-platform/pull/37094/files

image-20251017-041218.png
Users see this prompt while submitting content when post limit is reached.

4. Descriptive role information

  • When users hover over a username, a tooltip shows their role.

  • For learners, it says “Learner – taking the course just like you.”

  • For staff or moderators, it says “Staff [Moderator], part of the team that runs this course.”

  • This helps learners identify official posts and reduces the effect of fake authority names.

image-20251016-060056.png
Mouse-over on usernames shows tooltips that explains their role

5. Bulk delete option for course teams

  • A new option allows course staff and forum moderators to delete all forum content created by a specific user across a course or organization.

  • This is a hard delete that removes the data from the database.

  • Only staff/admin roles can access it from the options menu on a user’s tile in the Learners tab of the Discussions page.

Known Bug

At present, post deletion takes a several minutes each where as responses and comments are deleted in a reasonable time.

Option to delete forum content across course and across org

 

Confirmation message containing count of content that will be deleted

 

6. Verified email requirement

  • Almost all spam accounts used unverified or random email addresses.

  • A feature was built to allow forum posting only from verified accounts.

  • This setting remains behind a feature flag.

  • It was NOT released because:

    • It could reduce engagement by adding friction for genuine learners.

    • Spammers began verifying their emails. They learned about this by either watching the API call or PRs for the platform.

  • However, the feature remains available and can be activated if needed.

Configuration steps

  1. Enable the discussions.only_verified_users_can_post waffle flag on a specific course or the environment.

Pull requests

  1. https://github.com/openedx/edx-platform/pull/37046/files

  2. https://github.com/openedx/edx-platform/pull/37051/files

If a user with unverified email tries to create content, they will see this prompt.

Future Improvements

The measures above reduce the volume and visibility of spam and adds friction to creating spam.

Future improvements may include:

  1. Automated detection of spam content via AI.

  2. Moderation tools that help staff for example banning a learner from posting across org or platform.

  3. In-platform method for staff to raise request to disable an account.

The ultimate goal is to protect learners while keeping participation in course discussions easy and welcoming.