VisionSeq / docs /HARDENING.md
Antigravity Agent
Update docs, readme, and add project context
dc0d7c0
|
Raw
History Blame Contribute Delete
3.98 kB
# Operational Hardening
Security, reliability, and performance measures applied to the FastAPI backend, following the findings in [AUDIT.md](AUDIT.md).
---
## 1. Denial-of-Service Protection
Two layers guard against memory exhaustion from oversized or malicious payloads:
**Layer A β€” Boundary `Content-Length` check (middleware).**
A custom HTTP middleware in `main.py` inspects incoming `POST` requests before the body is read. If `Content-Length` exceeds the configured limit (5MB for `/predict`, 25MB for `/predict/batch`), the request is rejected immediately with `413 Payload Too Large`.
**Layer B β€” Defensive streaming check (endpoint level).**
If a client omits `Content-Length` or sends a spoofed value, the endpoint reads the file in bounded chunks and aborts once the cumulative size crosses the limit:
```python
contents = b""
chunk_size = 64 * 1024 # 64KB chunks
total_read = 0
while True:
chunk = await file.read(chunk_size)
if not chunk:
break
total_read += len(chunk)
if total_read > settings.MAX_FILE_SIZE_BYTES:
raise HTTPException(status_code=413, detail="File size exceeds limit")
contents += chunk
```
This closes the gap that header-only checks leave open β€” slow-post attacks and unbounded streams are terminated mid-transfer rather than after full buffering.
---
## 2. Event Loop Isolation
FastAPI's async endpoints run on a single-threaded event loop; synchronous CPU-bound work on that loop blocks *all* concurrent request handling, not just the request performing the work.
**Fix:** both image preprocessing (`preprocess_image()`) and the PyTorch forward pass are wrapped in a helper (`_process()`) dispatched via `run_in_threadpool()`.
**Effect:** the event loop stays free to accept and parse new connections while inference happens on background worker threads β€” the server handles concurrent uploads instead of serializing them behind whichever request is currently on the GPU/CPU.
---
## 3. Input Validation & MIME Security
Trusting client-reported `content_type` is insecure β€” filenames and MIME headers are trivially spoofable.
**Fix:** every uploaded buffer is validated with `PIL.Image.verify()`, which parses the actual image headers to confirm the file is structurally a valid image rather than an executable, archive, or corrupted payload.
**Exception mapping:** validation failures raise a `ValueError` inside the preprocessing pipeline, caught at the route level and converted to a logged `400 Bad Request` β€” never surfaced as an unhandled `500`.
---
## 4. Rate Limiting
An in-memory token-bucket limiter protects prediction endpoints from GPU/CPU exhaustion:
- **Algorithm:** per-IP token bucket, replenished at a fixed rate (2 requests/sec) up to a burst cap of 5.
- **Enforcement:** implemented as a FastAPI dependency (`rate_limit`), raising `429 Too Many Requests` once a client's bucket is depleted.
- **Known limitation:** state is process-local β€” a multi-instance deployment needs a shared backing store (e.g. Redis) for the limiter to be effective across replicas. Flagged in [AUDIT.md](AUDIT.md).
---
## 5. Observability
Hardened to support health monitoring and auditing in cloud environments (e.g. Kubernetes liveness/readiness probes):
- **Health metrics:** `/health` actively checks model readiness and GPU availability rather than returning a static `200`.
- **Service stats:** exposes model version, process uptime, and cumulative requests served.
- **Structured logging:** every request logs HTTP status, end-to-end latency (including upload streaming), raw inference time, and the resulting prediction or error β€” tagged with a request ID for tracing.
## Related Documentation
- [Engineering Audit](AUDIT.md) β€” the review that identified each issue addressed here
- [Architecture](ARCHITECTURE.md) β€” where these measures sit in the request lifecycle
- [API Specification](API.md) β€” the error codes these protections surface to clients