No description
  • Python 88%
  • HTML 11.6%
  • Shell 0.3%
  • Mako 0.1%
Find a file
2026-04-09 22:51:31 +00:00
alembic feat: P0 production readiness - PostgreSQL only, worker loop, dashboard, users pipeline 2026-04-06 16:05:58 -03:00
deploy ops: systemd units, helm chart stubs, federation protocol docs 2026-04-06 15:45:07 -03:00
docs ops: systemd units, helm chart stubs, federation protocol docs 2026-04-06 15:45:07 -03:00
fediguard Fix URL 2026-04-09 22:51:31 +00:00
helm/fediguard ops: systemd units, helm chart stubs, federation protocol docs 2026-04-06 15:45:07 -03:00
tests fix: credential status showing NOT CONFIGURED after save 2026-04-06 22:50:04 -03:00
.gitignore feat: FediGuard v0.2 - multi-tenant, federation, GUI, crypto, 182 tests 2026-04-06 01:21:42 -03:00
alembic.ini security: production hardening - SSRF, CSRF, audit, rate limiting, PII redaction 2026-04-06 15:38:41 -03:00
pyproject.toml security: production hardening - SSRF, CSRF, audit, rate limiting, PII redaction 2026-04-06 15:38:41 -03:00
README.md docs: comprehensive README for FediGuard v0.3 2026-04-06 15:49:46 -03:00
uv.lock security: production hardening - SSRF, CSRF, audit, rate limiting, PII redaction 2026-04-06 15:38:41 -03:00

 ______       _ _  _____                     _
|  ____|     | (_)/ ____|                   | |
| |__ ___  __| |_| |  __ _   _  __ _ _ __ __| |
|  __/ _ \/ _` | | | |_ | | | |/ _` | '__/ _` |
| | |  __/ (_| | | |__| | |_| | (_| | | | (_| |
|_|  \___|\__,_|_|\_____|\__,_|\__,_|_|  \__,_|

FediGuard

Autonomous spam protection for the Fediverse.

FediGuard is a self-hosted microservice that monitors email bounces from Mastodon instances, automatically detects and removes bot/spam accounts, blocklists disposable email domains, and federates blocklists with other instances via ActivityPub.

Built for instance administrators who are tired of manually hunting spam registrations. FediGuard watches your mail server, makes intelligent decisions, and acts — while keeping humans in the loop for edge cases.


What It Does

When someone registers on your Mastodon instance with a fake or disposable email, the confirmation email bounces. FediGuard catches that bounce and acts:

Bounce Type Action
Disposable domain (mailinator, guerrillamail, etc.) Block domain + delete account immediately
No TLS support Block domain (bot infrastructure)
Nonexistent mailbox on trusted provider (e.g. Gmail) Delete account only (don't block Gmail!)
Hard bounce from unknown domain Review on 1st occurrence, auto-block on 2nd
Soft bounce (temporary, quota full) Ignore completely

Every action is logged in an immutable audit trail. Users can appeal via a public form. Admins review everything through a terminal-aesthetic web GUI.


Architecture

                    ┌─────────────────────────────────────┐
                    │          PostgreSQL                  │
                    │  (encrypted credentials, blocklists, │
                    │   audit log, tenant config)          │
                    └──────────┬──────────┬───────────────┘
                               │          │
                 ┌─────────────┘          └──────────────┐
                 │                                       │
        ┌────────┴────────┐                    ┌─────────┴────────┐
        │  fediguard-web  │                    │ fediguard-worker  │
        │                 │                    │                   │
        │  FastAPI + HTMX │                    │  IMAP polling     │
        │  Admin GUI      │                    │  Bounce processing│
        │  OAuth2 login   │                    │  Domain blocking  │
        │  ActivityPub    │                    │  Account deletion │
        │  Health checks  │                    │  Rate limiting    │
        └────────┬────────┘                    └─────────┬────────┘
                 │                                       │
                 ├── Mastodon Admin API ─────────────────┤
                 │   (suspend/delete accounts,           │
                 │    email domain blocks)                │
                 │                                       │
                 └── Federation Peers ───────────────────┘
                     (ActivityPub blocklist exchange)

Two separate processes share the same PostgreSQL database:

  • Web serves the GUI, handles OAuth, exposes ActivityPub endpoints
  • Worker polls IMAP, processes bounces, executes actions

Features

Bounce Intelligence

  • RFC 3464 DSN parser with authenticity validation (rejects forged bounces)
  • Cross-references against 3 disposable email lists (5000+ domains)
  • DNS/MX analysis, Spamhaus RBL checks, reverse IP co-hosting detection
  • Rate-limited HackerTarget lookups for IP expansion
  • Safe domain protection — Gmail, Outlook, ProtonMail, Disroot, Riseup, etc. are never blocklisted

Multi-Tenant

  • Each Mastodon instance is a tenant with isolated data
  • Credentials (IMAP, Mastodon API token) encrypted with AES-256-GCM in PostgreSQL
  • Configure everything through the GUI — zero credentials in config files
  • OAuth2 login via Mastodon (admin/moderator role required)

Security Hardened

  • SSRF prevention on all outbound HTTP requests (private IP ranges blocked)
  • CSRF protection on all POST routes (itsdangerous tokens)
  • Bounce forgery detection (RFC 3464/5321 compliance checks)
  • Rate limiting (10 deletions/hour, 100 domain blocks/hour)
  • PII redaction in all logs (email hashing, IP masking)
  • Immutable audit log (cannot be updated or deleted, even by admins)
  • Security headers (CSP, HSTS, X-Frame-Options, Referrer-Policy)
  • Secret key validation (fail-fast on startup if default/missing)

Federation (ActivityPub)

  • Federate blocklists between FediGuard instances
  • PGP-signed blocks with revocation support
  • Per-peer circuit breaker (auto-pause after 5 consecutive failures)
  • Reciprocity tracking (detect free-rider peers)
  • Protocol versioning headers for forward compatibility

Compliance (LGPD/GDPR)

  • User appeals — public form, admin approve/reject workflow
  • Data retention — configurable per-table cleanup (bounces 90d, audit 2yr)
  • Data export — JSON export of all non-PII tenant data
  • Appeal link included in notification messages (DM + email)

Operational

  • Health checks (/health, /health/ready, /health/live) for Kubernetes
  • Graceful shutdown (SIGTERM handling, flush pending writes)
  • Alert system with deduplication (IMAP failures, API errors, rate limits)
  • Task visibility page with auto-refresh
  • Helm chart stubs and systemd service files

Quick Start

Prerequisites

  • Python 3.11+
  • PostgreSQL 14+
  • A Mastodon instance with admin access
  • An IMAP mailbox receiving bounce emails

Install

git clone https://github.com/popsolutions/fediguard.git
cd fediguard

# Install dependencies
uv sync  # or: pip install -e .

# Create PostgreSQL database
createdb fediguard

# Configure boot settings
cp .config/settings.env.example .config/settings.env
# Edit: set DATABASE_URL, SECRET_KEY, BASE_URL

Configure

The settings.env file only needs boot-level config:

# Required
DATABASE_URL=postgresql://fediguard:password@localhost/fediguard
SECRET_KEY=<generate with: python3 -c 'import secrets; print(secrets.token_hex(32))'>
BASE_URL=https://fediguard.your-instance.social

# Environment
ENV=production
FORCE_HTTPS=true
ALLOWED_HOSTS=fediguard.your-instance.social

All credentials (Mastodon API token, IMAP host/user/password) are configured through the web GUI and stored encrypted in PostgreSQL. No secrets in files.

Run Database Migrations

alembic upgrade head

Start

# Web server (GUI + API + federation)
fediguard-web

# Worker (IMAP polling + bounce processing)
fediguard-worker

First Login

  1. Open https://fediguard.your-instance.social
  2. Click Admin Login — authenticates via Mastodon OAuth2
  3. Go to SETTINGS — enter your Mastodon admin token and IMAP credentials
  4. Click Save Credentials — encrypted and stored in PostgreSQL
  5. The worker will start processing bounces on next poll cycle

GUI

Terminal-aesthetic interface built with HTMX + Alpine.js:

Page Purpose
Dashboard Bounce stats, recent activity
Bounces All processed bounce events with verdicts
Domains Blocked email domains (synced with Mastodon)
Users Flagged accounts pending review
Network Federation peers and reciprocity health
Tasks Background task results (auto-refresh)
Safelist Manage trusted domains + disposable list sources
Alerts Operational alerts (acknowledge/resolve)
Appeals User appeal requests (approve/reject)
Settings Tenant config + encrypted credential management
Audit Immutable log of all actions

Domain Classification Logic

Bounce received
  │
  ├─ Soft bounce (4.x.x)? → IGNORE
  │
  ├─ Safe domain (Gmail, etc.)?
  │   ├─ Nonexistent mailbox? → DELETE account (don't block domain)
  │   └─ Other bounce? → IGNORE
  │
  ├─ Already blocked? → IGNORE
  │
  ├─ No TLS? → BLOCK domain immediately
  │
  ├─ Disposable email list? → BLOCK domain
  │
  ├─ RBL listed IP? → BLOCK domain + co-hosted domains
  │
  └─ Hard bounce
      ├─ 1st occurrence → REVIEW (create UserReview for admin)
      └─ 2nd occurrence → BLOCK domain

Safety Guarantees

  • Soft bounces NEVER trigger any action — temporary issues are ignored
  • Trusted providers are NEVER domain-blocked — Gmail, Outlook, ProtonMail, Disroot, Riseup, and 15+ others are protected
  • Rate limiting prevents runaway deletions — max 10 accounts/hour, 50/day
  • Every action is audit-logged — immutable, with admin username and IP
  • Users can appeal — public form with no login required
  • Dry-run mode — test everything without executing actions

Tests

uv run pytest tests/ -v

359 tests covering:

  • Domain classification logic (safe domains, disposable, no-TLS, hard bounce thresholds)
  • DELETE_ACCOUNT_ONLY verdict for trusted domain + nonexistent mailbox
  • SSRF prevention (private IPs, localhost, metadata endpoints, DNS rebinding)
  • Bounce authenticity validation (RFC 3464 compliance)
  • Rate limiter (hourly/daily limits, independent actions)
  • Audit log immutability (cannot update or delete entries)
  • PII redaction (email hashing, IP masking, token redaction)
  • CSRF protection (valid/invalid/missing tokens)
  • Input validation (domain format, URL scheme, port restrictions)
  • Circuit breaker state machine (closed → open → half-open → closed)
  • Data retention (old records deleted, audit log preserved)
  • User appeals (submit, approve, reject, PII protection)
  • All web routes (auth, HTMX partials, CRUD operations)
  • Credential encryption (AES-256-GCM roundtrip, partial updates)
  • Worker startup validation (DB, tenant, credentials)

Production Deployment

systemd

sudo cp deploy/systemd/fediguard-web.service /etc/systemd/system/
sudo cp deploy/systemd/fediguard-worker.service /etc/systemd/system/
sudo systemctl enable --now fediguard-web fediguard-worker

Kubernetes (Helm)

helm install fediguard helm/fediguard/ \
  --set env.SECRET_KEY=$(python3 -c 'import secrets; print(secrets.token_hex(32))') \
  --set env.DATABASE_URL=postgresql://... \
  --set env.BASE_URL=https://fediguard.your-instance.social

Health probes are preconfigured:

  • Liveness: GET /health/live
  • Readiness: GET /health/ready

Federation Protocol

FediGuard instances exchange blocklists via ActivityPub. See docs/federation-protocol.md for the full protocol specification.

{
  "type": "Add",
  "actor": "https://fediguard.example.com/federation/actor",
  "object": {
    "type": "FediGuardBlock",
    "domain": "spam.example.com",
    "reason": "DISPOSABLE",
    "pgp_signature": "-----BEGIN PGP SIGNATURE-----..."
  }
}

Project Structure

fediguard/
├── main.py                 # Legacy entrypoint + bounce processing cycle
├── worker.py               # Worker process (IMAP polling)
├── database.py             # 19 SQLAlchemy models
├── domain_judge.py         # Bounce classification engine
├── mastodon_client.py      # Mastodon Admin API client
├── bounce_watcher.py       # IMAP + RFC 3464 DSN parser
├── credentials.py          # AES-256-GCM credential management
├── settings.py             # Boot-level configuration
├── alerts.py               # Operational alerting
├── activitypub.py          # ActivityPub federation
├── federation.py           # Peer management + reciprocity
├── crypto.py               # PGP + AES encryption
├── notifier.py             # DM + email notifications
├── retroactive.py          # Retroactive domain scanning
├── scheduler.py            # APScheduler job definitions
├── security/
│   ├── ssrf.py             # SSRF prevention
│   ├── bounce_validator.py # RFC 3464 authenticity checks
│   ├── rate_limiter.py     # Token bucket rate limiting
│   ├── audit.py            # Immutable audit logging
│   ├── circuit_breaker.py  # Per-peer circuit breaker
│   └── logging.py          # PII-redacting log formatter
├── compliance/
│   ├── retention.py        # Data retention cleanup
│   └── appeals.py          # User appeal workflow
└── web/
    ├── app.py              # FastAPI factory + security middleware
    ├── auth.py             # OAuth2 via Mastodon
    ├── csrf.py             # CSRF protection
    ├── middleware.py        # Tenant resolution
    ├── schemas.py          # Pydantic input validation
    ├── routes/             # 11 route modules
    └── templates/          # 27 Jinja2 templates (HTMX)

License

AGPL-3.0

Author

Marcos MendezPop.Coop

Built to protect organica.social and the broader Fediverse from spam, bots, and disposable email abuse.