Overview
PassAgent runs a multi-layered threat detection system that analyzes authentication events, access patterns, and network behavior in real time. Detections are backed by Redis for sliding-window analysis and produce one of four response actions: block the request, require step-up authentication, warn the user, or send an alert. All detections are logged to the audit trail and trigger security webhook alerts.Anomaly types
| Type | Trigger | Default action |
|---|---|---|
brute_force | 5+ failed auth attempts in 5 minutes | block |
impossible_travel | Login from a geographically impossible location given elapsed time | step_up_auth |
suspicious_travel | Login from an unusual but not impossible location | warn |
new_device | Unrecognized device fingerprint | step_up_auth |
revoked_device | Device previously revoked by the user | block |
bulk_operation | 50+ vault operations (reads, shares, exports) in 60 seconds | step_up_auth |
ip_spray | Single IP targeting multiple accounts | block or challenge |
password_spray | Same password hash attempted across multiple accounts | block or challenge |
subnet_spray | Multiple IPs in the same /16 subnet targeting many accounts | block |
access_anomaly | Behavioral profiling score exceeds threshold | block or step_up_auth |
Response actions
| Action | Effect |
|---|---|
block | Request is denied. The user cannot proceed. |
step_up_auth | The user must re-authenticate or complete an additional verification step. |
warn | The request proceeds but a warning is logged and the user is notified. |
alert | A security alert is sent via webhook. The request may proceed. |
Brute force detection
Tracks failed authentication attempts per user using Redis rate limiting.| Parameter | Value |
|---|---|
| Threshold | 5 failures |
| Window | 300 seconds (5 minutes) |
| TTL | 600 seconds (10 minutes) |
| Action | block |
recordAuthEvent() increments the failure counter. When the threshold is exceeded, the system blocks further attempts and fires a brute_force security alert.
Credential spray detection
The spray detector identifies distributed attacks where an adversary targets multiple accounts from the same infrastructure.IP spray
Tracks the number of distinct accounts targeted from a single IP address.| Tier | Threshold | Window | Action | Block duration |
|---|---|---|---|---|
| Challenge | 3 accounts | 1 hour | challenge | — |
| Block | 6 accounts | 6 hours | block | 2 hours |
| Hard block | 10 accounts | 24 hours | block | 24 hours |
Password spray
Tracks the same password hash being used against multiple accounts.| Tier | Threshold | Window | Action | Block duration |
|---|---|---|---|---|
| Challenge | 3 accounts | 1 hour | challenge | — |
| Block | 5 accounts | 6 hours | block | 2 hours |
Subnet spray
Detects distributed spray attacks across a /16 subnet (first two octets).| Tier | Threshold | Window | Action | Block duration |
|---|---|---|---|---|
| Block | 15 accounts | 1 hour | block | 2 hours |
Redis key structure
| Key pattern | Data stored |
|---|---|
spray:ip_attempts:{ip} | Array of { email, timestamp } entries |
spray:pw_hash:{hashPrefix} | Array of { emailPrefix, ip, timestamp } entries |
spray:subnet:{octet1}.{octet2} | Array of { email, timestamp } entries |
spray:blocklist:{ip} | { reason, expiresAt, type } |
Email addresses are hashed before storage in spray detection records to protect user privacy. The hash is not cryptographic — it is used for deduplication only.
Block durations
| Level | Duration |
|---|---|
challenge | 30 minutes |
block | 2 hours |
hard_block | 24 hours |
BlocklistEntry is written to Redis with an expiration timestamp. All subsequent requests from that IP are rejected until the block expires.
Impossible travel detection
When you log in from a new IP address, the system geolocates both the current and previous access locations, then calculates the travel speed required to move between them in the elapsed time.Resolve IP location
Calls
resolveIpLocation() to geolocate the current IP. Returns city, country, and coordinates.Compare with last access
Retrieves the previous access location from Redis. If the IP is the same, no analysis is performed.
Analyze travel feasibility
Calculates distance (km), elapsed time, and resulting speed (km/h). Compares against known locations to determine confidence.
travelAnalysis object:
| Field | Description |
|---|---|
distanceKm | Distance between the two locations in kilometers |
speedKmh | Implied travel speed in km/h |
verdict | normal, suspicious, or impossible |
confidence | Confidence score from 0 to 1 |
Example: impossible travel detection
Example: impossible travel detection
A user logs in from New York at 2:00 PM, then from London at 2:30 PM. The distance is ~5,500 km and the elapsed time is 30 minutes, implying a speed of 11,000 km/h. This exceeds any commercial flight speed and is classified as
impossible travel.The system responds with step_up_auth and sends a security alert webhook.Bulk operation detection
Monitors the volume of sensitive vault operations (password reveals, shares, exports) per user.| Parameter | Value |
|---|---|
| Threshold | 50 operations |
| Window | 60 seconds |
| Action | step_up_auth |
Device trust
ThecheckDeviceTrust() function evaluates device status and returns an appropriate anomaly result:
| Device status | Result |
|---|---|
| Known and trusted | No detection |
| Unknown / new device | new_device — requires step-up auth |
| Revoked device | revoked_device — blocked |
Behavioral profiling
ThecheckAccessBehavior() function uses the behavioral profiling system to score access events. It evaluates:
- IP reputation and history
- User agent consistency
- Device fingerprint
- Resource access patterns
- Session characteristics
block or step_up_auth depending on severity.
Audit and alerting
All detected anomalies produce two outputs:Audit log entry
action:anomaly_detectedresource:authorvaultmetadata: anomaly type, reason, thresholds- Includes IP address and user agent
Security alert webhook
- Fired for
brute_force,impossible_travel,bulk_operation, and all spray detections - Includes user ID, IP address, and a description
- Fire-and-forget (does not block the request)