-
-
New Sweep (hero) — cover image, states the positioning in one glance
-
Surfaces — leads with "why SerpApi is load-bearing," your strongest asset for the SerpApi judge specifically
-
Method — shows the free-prefilter reasoning and the honesty section, strongest for "technical execution"
-
Findings — real ranked output, not a mockup
-
Overview — ties it together as a dashboard
-
Ceasefire
Google's AI Overview is citing phishing domains as sources for your brand. Ceasefire sweeps 10 search surfaces to catch it, ranks the danger, and drafts the takedown — before a customer does.
Inspiration
A customer forwards you a phishing email pointing at a domain one character off yours. You take it down. Three weeks later it happens again — different domain, same brand. Nobody checks whether Google's own AI Overview is citing the impersonator as a trustworthy source when someone asks about your brand, because until this year no API could even see that citation list. The tools that exist watch domain registrations, not where the fake actually surfaces — and a naive sweep of ten search surfaces costs 1,260 API calls, which is dead on a free tier and a joke on an enterprise one.
Google is vouching for your attacker, and nobody is watching for it. That's the gap Ceasefire fills.
What it does
Give Ceasefire a brand and its domain. It generates ~126 lookalikes (homoglyph, omission, transposition, insertion, TLD-swap, hyphenation, combosquat — Cyrillic confusables resolved to punycode), narrows that to 1–3 with free DNS/MX/HTTP checks, then sweeps ten SerpApi surfaces on the survivors only: Google Search, AI Overview, AI Mode, Play Store, App Store, Shopping, Maps/Local, YouTube, Images/Lens, Trends.
Findings rank CRITICAL → LOW by a documented heuristic — cited by Google's AI outranks everything else, because that's the finding with no URL for the victim to get suspicious of. Unregistered lookalikes are checked and can be defensively registered through name.com before an attacker gets there first. A takedown notice is drafted from measured case facts and held at draft → reviewed → signed — signing an unapproved notice is a hard 409, and nothing is ever sent automatically. A human is always the last step before anything leaves the building.
How we built it
FastAPI backend, Next.js/TypeScript frontend. Every expensive pipeline stage sits behind a free one: permutation generation and DNS/MX/HTTP prefiltering cost nothing; only 1–3 survivors ever reach SerpApi. A token bucket paces the sweep inside the 50/hour limit, no_cache is set on the two AI-citation calls specifically (a stale result there is a missed detection), and a 24h cache serves repeats at zero cost. Auth is Argon2id + httpOnly cookies, sha256-only token storage, and every resource loader filters on user_id and returns 404 instead of 403. services/egress.py resolves and pins the IP before connecting and re-validates every redirect hop. 194 tests, no network required.
Workflow: From Brand Name to Signed Notice
================================================================================================
BRAND + PRIMARY DOMAIN
================================================================================================
│
▼
┌──────────────────────────────────────────────────────────────────────────────────────────────┐
│ 1 · GENERATE │
│ 7 techniques from domain: homoglyph, omission, transposition, insertion, TLD-swap, │
│ hyphenation, combosquat │
└──────────────────────────────────────────────┬───────────────────────────────────────────────┘
│ ~126 candidates · free
▼
/──────────────────\ [ NO ] ┌────────────────┐
< DNS A/AAAA >──────────────────▶│ DROPPED │
\ resolves? / │ Defensive-reg │
\────────────────/ │ candidate │
│ └────────────────┘
│ [ YES ] ~40 survive
▼
┌──────────────────────────────────────────────────────────────────────────────────────────────┐
│ MX RECORDS PRESENT? │
│ flags mail_capable — phishing-ready (informational, not a filter) │
└──────────────────────────────────────────────┬───────────────────────────────────────────────┘
│
▼
/──────────────────\ [ NO ] ┌────────────────┐
< HTTP 200 + >──────────────────▶│ DROPPED │
\ a title? / │ Cannot impers- │
\────────────────/ │ onate: no page │
│ └────────────────┘
│ [ YES ] 1–3 survivors (~97% cut)
▼
┌──────────────────────────────────────────────────────────────────────────────────────────────┐
│ 2 · SWEEP │
│ The only paid stage — 10 SerpApi surfaces │
│ Token-bucket paced under 50/hour cap (typically 11–13 searches · worst case 25) │
└──────────────────────────────────────────────┬───────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────────────────────────────┐
│ 3 · SCORE │
│ Documented heuristic, no ML │
│ │
│ [ CRITICAL ] [ HIGH ] [ MEDIUM ] [ LOW ] │
│ cited by AI live + mail-capable local pack/commerce parked (name.com cand.) │
└──────────────────────────────────────────────┬───────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────────────────────────────┐
│ 4 · DRAFT NOTICE │
│ Case facts through a conditional template — never AI prose │
└──────────────────────────────────────────────┬───────────────────────────────────────────────┘
│
▼
/──────────────────\ [ NO ] ┌────────────────┐
< HUMAN reviews >──────────────────▶│ HTTP 409 │
\ and approves? / │ Signing │
\────────────────/ │ blocked │
│ └────────────────┘
│ [ YES ]
▼
================================================================================================
SIGNED
Delivery to the registrant is a separate, deliberate action
================================================================================================
Workflow Step-by-Step Overview
| Step | Phase | Description | Output / Transition |
|---|---|---|---|
| 0 | Input | BRAND + PRIMARY DOMAIN |
Input seed for typo/combosquat generation |
| 1 | 1 · GENERATE | Generates domain variations using 7 techniques: homoglyph, omission, transposition, insertion, TLD-swap, hyphenation, combosquat | ~126 candidates · free |
| Filter | DNS A/AAAA Resolves? | Checks whether candidate domains resolve to active IP addresses | No → Dropped (defensive candidate) Yes → ~40 survive |
| Enrich | MX Records Present? | Flags domains that are mail_capable (phishing-ready); purely informational |
Proceeds directly to HTTP check |
| Filter | HTTP 200 + Title? | Checks whether the host returns an active HTTP 200 code with an HTML title | No → Dropped (cannot impersonate, no page live) Yes → 1–3 survivors (~97% cut) |
| 2 | 2 · SWEEP | Only paid stage: queries 10 SerpApi surfaces under a 50/hour token-bucket cap | Typically 11–13 searches (worst case 25) |
| 3 | 3 · SCORE | Documented heuristic (no machine learning): - CRITICAL: Cited by AI (outranks everything)- HIGH: Live + mail-capable- MEDIUM: Local pack / commerce- LOW: Parked (→ name.com candidate) |
Prioritized candidate list |
| 4 | 4 · DRAFT NOTICE | Case facts assembled through conditional templates (never AI prose) | Prepared draft ready for legal review |
| Gate | Human Review & Approval | Human validation gate | No → HTTP 409 (signing unapproved notice blocked)Yes → Proceed to signing |
| Final | SIGNED | Final signed notice | Delivery to registrant is an explicit, separate action |
Brand + domain in
Stage 1 · Generate — free
permutations.py — 7 techniques (homoglyph, omission, transposition, insertion, TLD-swap, hyphenation, combosquat), Cyrillic confusables resolved to punycode.
→ ~126 candidates
Stage 2 · Prefilter — free
DNS resolves? No → dropped (surfaces as a defensive-registration candidate). Yes → ~40 survive. MX present? → flags mail_capable (phishing-ready). HTTP 200 with a title? No → dropped.
→ 1–3 survivors, a ~97% reduction, zero paid calls so far
Stage 3 · Sweep — the only paid stage
serpapi.py + sweep.py, 10 surfaces, token-bucket paced: Google Search (1 search per survivor), AI Overview (2 searches, no_cache), AI Mode (1 search, no_cache), plus 7 brand engines (1 search each, cacheable).
→ typically 11–13 searches per sweep, worst case 25
Stage 4 · Score — documented heuristic, no ML CRITICAL — cited in AI Overview or AI Mode. HIGH — live and mail-capable, or an app-store listing. MEDIUM — local pack or commerce listing. LOW — parked or unregistered, a name.com candidate.
Stage 5 · Notice — human always in the loop draft → reviewed → signed. Signing an unapproved notice is a hard 409. Nothing is ever delivered automatically.
Where this lines up with the tracks we're entering:
| SerpApi — Best AI Use Case (criteria: originality, technical execution, SerpApi integration, usability, potential impact) | What we built |
|---|---|
| Originality | AI Overview / AI Mode citation checking — a harm class the API to detect only exists this year, and one the domain-monitoring incumbents don't check |
| Technical execution | Token-bucket rate limiter, 24h cache, no_cache set deliberately on verification paths, SSRF-guarded egress, 194 tests |
| SerpApi integration | 10 of 10 engines used with a purpose each; AI Overview's page_token handled inline per-result (it expires in under 60s) |
| Usability | One input — brand + domain. No config. Demo login seeded, no signup required to evaluate |
| Potential impact | Naive sweep: 1,260 searches. Ours: 2–4. That gap is what makes this affordable below enterprise brand-protection pricing |
| name.com — Domain API Challenge (criteria: API integration depth, creativity, technical execution, real-world viability, presentation) | What we built |
|---|---|
| API integration depth | checkAvailability + register, both live in the pipeline (sandboxed by default) — not a single surface-level lookup |
| Creativity | Registration is driven by the scan itself: unregistered lookalikes surface as defensive-registration candidates, not a bolt-on search box |
| Technical execution | Sandbox-vs-production is an explicit config flag that logs loudly, so a demo can't accidentally register a real domain |
| Real-world viability | The cheapest takedown that exists — buying the lookalike yourself before the attacker does |
| Presentation | Live in the Domains view alongside the sweep that produced the candidate |
Challenges we ran into
The real one: our first token bucket had a burst of 10, but a single sweep spends 11–25 searches. The first sweep drained the burst instantly; every sweep after paid the full 72-second refill per search — a second 12-search sweep that should've taken seconds measured at 14.4 minutes. We'd also hardcoded a "~20s" scan estimate in the UI that was just a guess. We deleted it and repaced the bucket to 1 token/second with a burst of 30. Second one: deploying to a managed host handed us a postgres:// URL that SQLAlchemy resolves to psycopg2, but we'd shipped psycopg3 — the process died on import, silently, until we normalized the URL prefix ourselves.
Accomplishments that we're proud of
The economics, measured, not claimed: naive sweep 1,260 searches, ours 2–4. That's the whole product. We're also proud of what we refused to build: no confidence scores, no false-positive rate we haven't measured, no automated takedown delivery, no * in CORS. And of catching our own dishonesty before a judge would — Settings used to claim every integration was "connected" including one returning a live 403; it now reports not_configured from real state.
What we learned
Short-lived tokens and rate-limited free tiers punish naive orchestration immediately and specifically — the bug isn't abstract, it's a 14-minute sweep in front of a judge. And that the most convincing thing you can put in front of a security-minded evaluator isn't a feature — it's the list of features you deliberately didn't build, printed under a heading that says so.
What's next for Ceasefire
A labelled evaluation set to replace "documented heuristic" with a measured false-positive rate. A scan study across more brands to publish an aggregate exposure number.
Built With
- argon2
- dnspython
- fastapi
- httpx
- lenis
- name.com-api
- nextjs
- postgresql
- pydantic
- pytest
- python
- react
- serpapi
- sqlalchemy
- sqlite
- tailwindcss
- three.js
- typescript
- uvicorn
- vercel

Log in or sign up for Devpost to join the conversation.