Skip to content
This repository was archived by the owner on Jun 19, 2026. It is now read-only.

feat: login anomaly detection & suspicious activity alerts (#124)#1074

Open
Entr0zy wants to merge 1 commit into
rohitdash08:mainfrom
Entr0zy:feat/login-anomaly-124
Open

feat: login anomaly detection & suspicious activity alerts (#124)#1074
Entr0zy wants to merge 1 commit into
rohitdash08:mainfrom
Entr0zy:feat/login-anomaly-124

Conversation

@Entr0zy

@Entr0zy Entr0zy commented May 24, 2026

Copy link
Copy Markdown

Login anomaly detection & suspicious activity alerts

Production-ready login fingerprinting and anomaly detection for issue #124.

What's added

Models (app/models.py)

  • LoginEvent — every login attempt stored with SHA-256-hashed IP & user-agent (PII-safe), masked display IP (e.g. 192.168.1.xxx), success flag, failure reason
  • SecurityAlert — stored alert with type, severity (low/medium/high), message, acknowledged flag, link to triggering event
  • AlertType enum: new_ip | new_device | failed_burst | unusual_hour
  • AlertSeverity enum: low | medium | high

Service (app/services/anomaly.py)

  • record_login_event() — hashes & masks PII before storing
  • check_and_create_alerts() — runs all four detection rules atomically with the event

Detection rules:

Rule Trigger Severity
new_ip IP hash not seen in last 20 successful logins medium
new_device UA hash not seen in last 20 successful logins medium
failed_burst ≥5 failures in 15-minute window (deduped — one alert per window) high
unusual_hour Login between 00:00–04:59 UTC low

Routes (app/routes/security.py, at /security)

Method Path Description
GET /security/events Login history (most recent first, ?limit=N)
GET /security/alerts All alerts (?unread_only=true supported)
GET /security/alerts/unread-count Badge count for UI
PATCH /security/alerts//acknowledge Mark alert as read

Auth integration (app/routes/auth.py)

  • /auth/login now records every attempt (success or failure)
  • On success: anomaly detection runs; security_alerts list included in response when anomalies found (key absent for clean logins)
  • Failures still recorded for burst detection; anomaly errors are caught and logged without breaking login flow

Tests (tests/test_anomaly.py) — 28 tests, all green

  • Auth gates (401 without JWT)
  • Event recording on success & failure; IP masking verification
  • new_ip alert: first login → no alert; known IP → no alert; new IP → alert
  • new_device alert: same UA → no alert; new UA → alert
  • failed_burst: below threshold → no alert; threshold → alert; 10 failures → only 1 alert (dedup verified)
  • unusual_hour: injected 02:30 UTC → alert; 10:00 UTC → no alert
  • Alert endpoints: list, unread filter, unread count, acknowledge
  • Cross-user isolation (404 for other user's alert)
  • Login response security_alerts present when anomalies found; absent on clean login

/claim #124


🤖 Generated with Claude Code

…08#124)

Adds production-ready login fingerprinting, anomaly detection, and
security alert infrastructure.

Models (app/models.py):
- LoginEvent   — records every login attempt with SHA-256-hashed IP/UA,
                 masked display IP, success flag, and failure reason
- SecurityAlert — stored alert with type, severity, message, acknowledged
                  flag, and link to triggering LoginEvent
- AlertType enum: new_ip | new_device | failed_burst | unusual_hour
- AlertSeverity enum: low | medium | high

Service (app/services/anomaly.py):
- record_login_event() — hashes & masks PII before storing
- check_and_create_alerts() — runs all detection rules atomically
- new_ip        (medium) — IP hash not seen in last 20 successful logins
- new_device    (medium) — UA hash not seen in last 20 successful logins
- failed_burst  (high)   — >=5 failures in 15-minute window (deduped)
- unusual_hour  (low)    — login between 00:00-04:59 UTC
- get_login_history(), get_alerts(), acknowledge_alert()

Routes (app/routes/security.py, registered at /security):
  GET   /security/events                     login history (limit param)
  GET   /security/alerts                     all/unread alerts
  GET   /security/alerts/unread-count        badge count
  PATCH /security/alerts/<id>/acknowledge    mark as read

Auth integration (app/routes/auth.py):
- /auth/login now records every attempt (success or failure)
- On success: runs anomaly detection, returns security_alerts list in
  response body (key omitted when no anomalies found)
- Failures still recorded for burst-detection; anomaly errors are
  caught and logged without breaking the login flow

Tests (tests/test_anomaly.py): 28 tests, all green
- Auth gates (401 without JWT)
- Event recording on success & failure; IP masking
- new_ip alert: first login → no alert; known IP → no alert; new IP → alert
- new_device alert: same UA → no alert; new UA → alert
- failed_burst: below threshold → no alert; threshold reached → alert;
  10 failures → only 1 alert (dedup)
- unusual_hour: injected 02:30 UTC → alert; 10:00 UTC → no alert
- Alert endpoints: list, unread filter, unread count, acknowledge
- Cross-user isolation (404 for other user's alert acknowledge)
- Login response includes security_alerts key when anomalies detected;
  key absent on clean login

Closes rohitdash08#124

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant