Open source on GitHub

Keep your repo
🤬Potty Mouth
free.

A drop-in GitHub Action that scans issues, pull requests, and comments for profane content — then replaces it with the strategy of your choice. Built with .NET Native AOT for instant, dependency-free runs.

MIT licensed · No registration · Works with the built-in GITHUB_TOKEN

.github/workflows/profanity-filter.ymlyaml
# .github/workflows/profanity-filter.yml
name: Profanity filter

on:
  issues:
    types: [opened, edited, reopened]
  pull_request:
    types: [opened, edited, reopened]
  issue_comment:
    types: [created, edited]

permissions:
  issues: write
  pull-requests: write

jobs:
  apply-filter:
    runs-on: ubuntu-latest
    steps:
      - name: Scan for profanity
        if: github.actor != 'dependabot[bot]'
        uses: IEvangelist/profanity-filter@main
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          replacement-strategy: emoji
6,500+
Curated words
across the dictionary
28
Languages
globally inclusive
14
Replacement strategies
for every taste
Native AOT
.NET 10 powered
instant cold starts
263K+
Container pulls
trusted from GHCR
See it in action

Live filtering, every keystroke.

A typewriter pours a sentence into the input below — the same logic that runs in the WebApi container then redacts each profane word, side-by-side, in every strategy. No backend, no SignalR — just JavaScript mirroring MatchEvaluators.cs.

potty-mouth · live filter
Input

All 14 strategies — updating live, every keystroke

Identical logic to MatchEvaluators in the WebApi.

  • asterisk

    AsteriskClassic asterisks

  • random-asterisk

    Random asteriskRandom count, 1–N

  • middle-asterisk

    Middle asteriskKeep first + last

  • first-letter-then-asterisk

    First letter + asteriskKeep first only

  • vowel-asterisk

    Vowel asteriskAsterisk the vowels

  • emoji

    EmojiRandom expressive emoji

  • anger-emoji

    Anger emojiRandom anger emoji

  • middle-swear-emoji

    Middle swear emojiFirst + 🤬 + last

  • bleep

    BleepLiteral "bleep"

  • redacted-rectangle

    Redacted rectangleSolid █ blocks

  • strike-through

    Strike throughWraps in <del>

  • underscores

    UnderscoresUnderscores match length

  • grawlix

    GrawlixComic-book symbols

  • bold-grawlix

    Bold grawlixGrawlix, but louder

Live, in-browser demonstration of every replacement strategy. A sample sentence containing profane words is typed character-by-character into the input field, and each of the fourteen strategy panels below updates in real time to show how that strategy filters the matched words.
Text alternative — what the live demo shows
  1. A typewriter animation enters a sample sentence (e.g. This shit is broken, what the hell are we doing here?) into the input panel at the top, one character at a time.
  2. Beneath the input is a grid of 14 cards, one per replacement strategy. Each card shows the strategy's slug, a friendly label, and a one-line description.
  3. On every keystroke, every card re-renders the input with that card's strategy applied. Profane words are matched as whole words (case-insensitive).
  4. The moment the input contains a completed profane word, a GitHub-style profane content 🤬 label appears above the input — emulating the label the GitHub Action applies to flagged issues and pull requests. It links to the label documentation, and disappears again if the input clears to something clean.
  5. For example: asterisk turns shit into ****, middle-asterisk turns it into s**t, bleep replaces it with the literal word bleep, and middle-swear-emoji turns it into s🤬t.
  6. When the sentence finishes typing, the demo pauses briefly, clears, and starts typing a new sentence. The toggle button in the top-right lets you pause or resume the animation.
  7. The filtering logic is a faithful port of MatchEvaluators.cs in the .NET library — the same code that powers the GitHub Action and the WebApi container.

Prefer the original SignalR-driven recording? It now lives next to the WebApi container README — same Aspire AppHost in playground/apphost.cs, streaming text over a SignalR hub and client.

Why bother?

Not every contributor issunshine and rainbows.

Open source is a public-facing space, and the tone of a project sets the tone of its community. Potty Mouth quietly catches the rough edges — rewriting profane content, flagging the issue, and leaving a clean audit trail behind — so you can keep building without playing comment-thread cop.

With this action in your workflow, your repo can be🌈 invitingand🐎 swift.

  • Live rewrite — comments stay readable
  • Auto-label issues for triage
  • Audit-friendly job summaries
DV@grumpy-dev · 2m
raw

thisshitbroke prod again — what thehellis going on with thisdamnCI 🙄

DV@grumpy-dev · 2m · edited by bot
filtered

this💩broke prod again — what the🤬is going on with this😡CI 🙄

profaneneeds-review
What's inside

Everything you need. Nothing you don't.

One step in your workflow, fourteen strategies, twenty-eight languages, and a clean job summary on every run.

🌍

28 languages, 6,500+ words

Curated word lists across 28 languages — English, Spanish, French, German, Italian, Portuguese, Russian, Dutch, Polish, Turkish, Japanese, Korean, Arabic, Chinese, Hindi, and more — kept up to date in plain text files anyone can audit.

🎨

14 replacement strategies

Pick the vibe — from classic **** asterisks to playful 😡 anger emojis or full ████ redactions.

⚡

Native AOT performance

Built with .NET 10 and Native AOT — instant cold starts, tiny binaries, and no .NET runtime to install on the runner.

🧩

Drop-in step

A single GitHub Action step. Add it to a new workflow or paste it into an existing one — no scripts, no infrastructure, no maintenance.

📊

Workflow job summaries

Every run produces a clean, detailed summary table showing exactly what was found and how it was replaced — perfect for audits.

🔧

Bring your own words

Extend the dictionary with a comma-separated list or pull from your own URL. Works alongside the built-in filters automatically.

Replacement strategies

14 ways to say that word.

Pick the strategy that fits your project's tone — from buttoned-up to playful.

asterisk****

Classic asterisks — the safe default.

emoji💩

A random expressive emoji per match.

grawlix#%$!

Comic-book style symbol soup.

bold-grawlix#%$!

Grawlix, but louder.

bleepbleep

Replaces with the literal word "bleep".

redacted-rectangle████

Top-secret redaction blocks.

anger-emoji😡

A random anger-themed emoji.

middle-asteriskf**k

Keeps first and last letters intact.

middle-swear-emojif🤬k

A swear emoji in the middle.

random-asterisk* — ****

Random number of asterisks.

first-letter-then-asteriskf***

Keep the first letter only.

vowel-asterisksh*t

Replaces only the vowels.

strike-throughshit

Wraps content in &lt;del&gt; tags.

underscores____

Replaces with underscores.

Also for Aspire

More than a GitHub Action.

The same engine ships as a containerized Aspire resource. DropAddProfanityFilterinto your AppHost — in C# or TypeScript — and you have a fast, local-first HTTP filter alongside the rest of your services.

// apphost.cs
var builder = DistributedApplication.CreateBuilder(args);

var filter = builder.AddProfanityFilter("profanity-filter")
    .WithCustomDataBindMount("./CustomData");

builder.AddProject<Projects.MyApi>("api")
    .WithReference(filter)
    .WaitFor(filter);

builder.Build().Run();

Ready to clean up your repo?

Two minutes from this page to a working workflow. No registration, no infrastructure, no excuses.