brentley / brentley/data-profiler
Security: Configure Uvicorn to validate X-Forwarded-For headers
- Dominant language
- Python
- Stars
- 0
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
The API currently trusts `X-Forwarded-For` headers from any client without validation, which creates security concerns for production deployments.
## Problem
Uvicorn (the ASGI server) trusts `X-Forwarded-For` headers by default. This means:
- Any client can spoof their IP address in logs
- If client IPs are used for rate limiting, access control, or security decisions, they can be bypassed
- Logs show proxy/CDN IPs instead of actual client IPs when behind a reverse proxy
## Evidence
```bash
# Test showing header spoofing works:
curl -H "X-Forwarded-For: 151.101.194.132" http://localhost:8000/healthz
# Logs show: INFO: 151.101.194.132:46074 - "GET /healthz HTTP/1.1" 200 OK
# Instead of: INFO: 127.0.0.1:46074 - "GET /healthz HTTP/1.1" 200 OK
```
## Security Impact
- **Low** for local development (current state)
- **Medium** for production without proper proxy configuration
- **High** if IP-based access control or rate limiting is implemented
## Recommended Fix
Configure Uvicorn with `--forwarded-allow-ips` to only trust headers from known proxy IPs:
### Option 1: No Reverse Proxy (Direct Internet Access)
```python
# Dockerfile or docker-compose.yml
CMD ["uvicorn", "api.app:app", "--host", "0.0.0.0", "--port", "8000", "--forwarded-allow-ips", ""]
```
### Option 2: Behind Reverse Proxy (Cloudflare, nginx, etc.)
```python
# For Cloudflare Tunnel
CMD ["uvicorn", "api.app:app", "--host", "0.0.0.0", "--port", "8000", "--forwarded-allow-ips", "172.16.0.0/12"]
# For nginx/traefik
CMD ["uvicorn", "api.app:app", "--host", "0.0.0.0", "--port", "8000", "--forwarded-allow-ips", "172.18.0.1"]
```
### Option 3: Auto-detect Docker Network (Recommended)
Use environment variable to configure based on deployment:
```yaml
# docker-compose.yml
environment:
FORWARDED_ALLOW_IPS: "${FORWARDED_ALLOW_IPS:-}" # Empty by default
```
```python
# Dockerfile ENTRYPOINT script
forwarded_ips="${FORWARDED_ALLOW_IPS:-}"
uvicorn api.app:app --host 0.0.0.0 --port 8000 --forwarded-allow-ips "$forwarded_ips"
```
## Implementation Checklist
- [ ] Add `FORWARDED_ALLOW_IPS` environment variable to `.env.example`
- [ ] Update Dockerfile/docker-compose.yml to use the variable
- [ ] Document the setting in README or deployment docs
- [ ] Test with Cloudflared tunnel (if using Cloudflare)
- [ ] Verify logs show correct IPs after fix
## References
- [Uvicorn Deployment: Running behind a proxy](https://www.uvicorn.org/deployment/#running-behind-nginx)
- [FastAPI: Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/)
## Priority
**Must fix before production deployment**
Contributor guide
No contributing guide indexed for this repository
Research direction
Inspect the current Uvicorn command in Dockerfile and docker-compose.yml, plus .env.example and the README or deployment documentation. Start by checking how the application is launched and reproduce the documented curl request; configure the forwarded-IP setting for the supported deployment modes, document it, and verify that logs no longer accept spoofed client addresses.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, fastapi, python
- Domain
- backend, devops, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100