# Security Best Practices Reference

## Sources and Citations

This document compiles authoritative security guidance for the Iron Vault FSAL.

---

## 1. Path Traversal Prevention

### OWASP Path Traversal
**URL:** https://owasp.org/www-community/attacks/Path_Traversal
**Key Guidance:**
- Never trust user-supplied input for file paths
- Use allowlists, not blocklists
- Canonicalize paths before validation
- Validate after all path manipulation is complete

### PortSwigger Web Security Academy
**URL:** https://portswigger.net/web-security/file-path-traversal
**Key Guidance:**
- Test for encoded variants: `%2e%2e%2f`, `..%2f`, `%2e%2e/`
- Test for double-URL encoding: `%252e%252e%252f`
- Test for null byte injection: `../../../etc/passwd%00.png`
- Validate the canonical path starts with expected base

### Python-Specific: path-jail-python
**URL:** https://github.com/aimable100/path-jail-python
**Key Guidance:**
- Use dedicated sandbox libraries
- Prevent escapes via symlinks
- Handle edge cases like `~` expansion

---

## 2. Atomic File Operations

### python-atomicwrites Documentation
**URL:** https://python-atomicwrites.readthedocs.io/en/latest/
**Key Pattern:**
```python
import os
import tempfile

def atomic_write(path, data):
    dir_name = os.path.dirname(path)
    with tempfile.NamedTemporaryFile('w', dir=dir_name, delete=False) as tf:
        tf.write(data)
        tf.flush()
        os.fsync(tf.fileno())
        tempname = tf.name
    os.replace(tempname, path)
    # CRITICAL: fsync directory after rename
    dirfd = os.open(dir_name, os.O_DIRECTORY)
    os.fsync(dirfd)
    os.close(dirfd)
```

### LWN.net: Atomic Writes Without Tears
**URL:** https://lwn.net/Articles/974578/
**Key Insights:**
- Filesystem-specific behaviors vary
- Btrfs, XFS, ext4 have different guarantees
- For maximum safety, fsync both file AND directory

---

## 3. TOCTOU Race Conditions

### CWE-367: Time-of-check Time-of-use (TOCTOU) Race Condition
**URL:** https://cwe.mitre.org/data/definitions/367.html
**Key Guidance:**
- Eliminate check-then-use patterns
- Use atomic operations where possible
- Use file descriptor operations instead of paths
- Use `O_CREAT | O_EXCL` for secure file creation

### CVE-2026-22701: Python filelock Vulnerability
**URL:** https://www.sentinelone.com/vulnerability-database/cve-2026-22701/
**Lesson Learned:**
- Even well-tested libraries can have TOCTOU bugs
- Symlink attacks between check and use are common
- Use `O_NOFOLLOW` flag where possible

### Pythonic EAFP Pattern
```python
# BAD: Check-then-use (TOCTOU vulnerable)
if os.path.exists(path):
    with open(path) as f:
        data = f.read()

# GOOD: EAFP (Easier to Ask Forgiveness than Permission)
try:
    with open(path) as f:
        data = f.read()
except FileNotFoundError:
    # handle missing file
except PermissionError:
    # handle permission issue
```

---

## 4. FastAPI Security

### FastAPI Official Security Docs
**URL:** https://fastapi.tiangolo.com/tutorial/security/
**Key Topics:**
- OAuth2 with JWT
- Password hashing with bcrypt
- HTTPS requirement

### FastAPI Security Best Practices (2024-2025)
**URL:** https://escape.tech/blog/how-to-secure-fastapi-api/
**Checklist:**
- [ ] Use HTTPS in production
- [ ] Implement rate limiting
- [ ] Configure CORS properly
- [ ] Add security headers
- [ ] Validate all inputs with Pydantic
- [ ] Protect documentation endpoints
- [ ] Use constant-time comparison for tokens

### Rate Limiting with slowapi
**URL:** https://github.com/laurentS/slowapi
```python
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

@app.post("/v1/fs/write")
@limiter.limit("100/minute")
async def write_file(request: Request, ...):
    ...
```

---

## 5. Production Deployment

### FastAPI Production Deployment Guide
**URL:** https://fastapi.tiangolo.com/deployment/concepts/
**Key Points:**
- Use Gunicorn as process manager
- Use Uvicorn workers for async
- Place behind reverse proxy (NGINX)
- Enable HTTPS

### Gunicorn + Uvicorn Configuration
```python
# gunicorn.conf.py
workers = 4
worker_class = "uvicorn.workers.UvicornWorker"
bind = "0.0.0.0:4848"
timeout = 30
keepalive = 2
errorlog = "-"
accesslog = "-"
```

### Docker Security Best Practices
**URL:** https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html
**Checklist:**
- [ ] Use non-root user
- [ ] Use multi-stage builds
- [ ] Minimize installed packages
- [ ] Use read-only root filesystem where possible
- [ ] Set resource limits
- [ ] Scan images for vulnerabilities

---

## 6. Token Security

### Constant-Time Comparison
```python
import hmac

def secure_compare(a: str, b: str) -> bool:
    """Constant-time string comparison to prevent timing attacks."""
    return hmac.compare_digest(a.encode('utf-8'), b.encode('utf-8'))
```

### Token Best Practices
- Use cryptographically random tokens: `secrets.token_urlsafe(32)`
- Minimum 256 bits of entropy
- Store tokens hashed in production databases
- Rotate tokens periodically
- Log token usage for audit trail

---

## 7. Structured Logging

### structlog for Python
**URL:** https://www.structlog.org/
```python
import structlog

structlog.configure(
    processors=[
        structlog.stdlib.filter_by_level,
        structlog.stdlib.add_logger_name,
        structlog.stdlib.add_log_level,
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.processors.JSONRenderer(),
    ],
)

logger = structlog.get_logger()
logger.info("file_read", path=path, size=len(data), client_ip=client_ip)
```

### Security-Relevant Events to Log
- Authentication attempts (success/failure)
- Authorization decisions
- File operations (read/write/delete)
- Configuration changes
- Rate limit hits
- Sandbox violation attempts

---

## 8. Health Checks

### Kubernetes-style Probes
```python
@app.get("/healthz")
def health_check():
    """Liveness probe - is the service running?"""
    return {"status": "ok"}

@app.get("/readyz")
def readiness_check():
    """Readiness probe - is the service ready to accept traffic?"""
    sandbox_ok = validate_sandbox_config()["configured"]
    return {"ready": sandbox_ok}
```

---

## Quick Reference Links

| Topic | URL |
|-------|-----|
| OWASP Path Traversal | https://owasp.org/www-community/attacks/Path_Traversal |
| OWASP Docker Security | https://cheatsheetseries.owasp.org/cheatsheets/Docker_Security_Cheat_Sheet.html |
| FastAPI Security | https://fastapi.tiangolo.com/tutorial/security/ |
| python-atomicwrites | https://python-atomicwrites.readthedocs.io/ |
| CWE-367 TOCTOU | https://cwe.mitre.org/data/definitions/367.html |
| structlog | https://www.structlog.org/ |
| slowapi | https://github.com/laurentS/slowapi |

---

*Last updated: 2026-02-08*
