C.W.K.
Stream
Lesson 04 of 05 · published

The Blacklist — Storage, Lift, Audit

~15 min · blacklist, auto-lift, admin

Level 0Greenhorn
0 XP0/53 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

The blacklist is your last line of defense before brute force succeeds. It needs to be: durable (survives restart), liftable (you can release a wrongly-blacklisted IP — your own, usually), and auditable (you can see why each entry was added).

Releasing an entry — admin-only

Auto-lift vs manual-lift — the trade

ModeHowProCon
ManualAdmin clicks unblock when neededForces a human in the loop; you notice patternsYou lock yourself out, you can't unblock from the locked-out machine
Time-based auto-liftEntries expire after, e.g., 24 hoursSelf-healing; can't permanently lock yourself outPersistent attackers just wait 24h and retry
Hybrid"exceeded_retry" auto-lifts after 1h; "honeypot" stays foreverBest of bothMore code (worth it)

Code

Schema (also in Track 5)·sql
CREATE TABLE security_blacklist (
  ip          TEXT PRIMARY KEY,
  reason      TEXT,
  blocked_at  INTEGER NOT NULL
);
Admin-only unblock endpoint·python
@app.post("/admin/security/unblock")
async def unblock(request: Request, ip: str = Form(...)):
    require_admin(request)
    db.execute("DELETE FROM security_blacklist WHERE ip = ?", (ip,))
    db.execute("DELETE FROM security_attempts  WHERE ip = ?", (ip,))
    db.commit()
    return RedirectResponse("/admin/security", status_code=302)
Hybrid auto-lift sweep·python
RETRY_BLOCK_TTL = 3600   # 1 hour

def auto_lift_blacklist():
    cutoff = now() - RETRY_BLOCK_TTL
    db.execute("""
      DELETE FROM security_blacklist
      WHERE reason = 'exceeded_retry' AND blocked_at < ?
    """, (cutoff,))
    db.commit()

# Run on app startup; or as a periodic task; or before each login attempt

External links

Exercise

Add the unblock endpoint and the auto_lift_blacklist function. Schedule auto_lift_blacklist via FastAPI's startup event or a background task. Test: trigger a lockout, wait an hour (or temporarily set RETRY_BLOCK_TTL=10), confirm the entry is gone. Honeypot entries should remain.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.