brentley / brentley/data-profiler

Security: Configure Uvicorn to validate X-Forwarded-For headers

Open
#49 0 comments 0 reactions 0 assignees View on GitHub
enhancement security
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.