Last Updated: 2025-11-25Documentation Index
Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
Use this file to discover all available pages before exploring further.
Status: ✅ Implemented
Overview
The Encore Health OS Reporting Engine allows users to create custom SQL queries for generating reports. This document outlines the security measures implemented to prevent SQL injection, data breaches, and performance abuse.Critical Security Measures
1. Parameterized Query Execution
Problem: String replacement of parameters ({{param}}) is vulnerable to SQL injection.
Solution: Use PostgreSQL prepared statements with numbered parameters ($1, $2, etc.).
2. Query Complexity Validation
Problem: Complex queries can cause performance degradation or denial of service. Solution: Implement query complexity limits:- Max 5 JOINs - Prevents cartesian product explosions
- Max 3 subqueries - Limits nested query depth
- No UNION ALL - Prevents expensive full table scans
- No window functions - Deferred until performance impact is understood
3. Enhanced Audit Logging
Problem: Lack of visibility into executed queries makes incident response difficult. Solution: Log all report executions with:- Actual executed SQL (with resolved parameters)
- User ID and timestamp
- IP address and user agent
- Execution time and row count
- Success/failure status
4. Row-Level Security (RLS)
All queries execute under the authenticated user’s RLS context:5. Database Function Security
Theexecute_report_query function runs with SECURITY DEFINER but:
- Only allows
SELECTstatements - Blocks dangerous keywords (
DROP,ALTER,INSERT,UPDATE,DELETE, etc.) - Enforces row limit (10,000 rows max)
- Enforces query timeout (30 seconds max)
Security Best Practices
For Developers
- Never bypass parameterization - Always use
buildParameterizedQuery() - Validate all inputs - Check parameter types and ranges
- Test with malicious inputs - Use SQL injection test cases
- Monitor query patterns - Look for anomalous query structures
- Review audit logs regularly - Detect suspicious activity
For Report Authors
- Use parameters for all user inputs - Never concatenate user data into SQL
- Test with minimal data first - Verify query performance before production
- Request only needed columns - Avoid
SELECT * - Use indexes - Ensure WHERE clauses use indexed columns
- Review generated SQL - Use dry-run mode to inspect query structure
For Security Reviewers
-
Audit
pf_report_executionslogs - Look for:- Failed queries with injection patterns
- Queries with excessive execution time
- High-volume queries from single users
- Queries accessing sensitive tables
-
Monitor resource usage - Alert on:
- Query execution time > 10 seconds
- Row counts > 5,000
- Multiple failed queries from same user
-
Review report definitions - Flag reports that:
- Join more than 3 tables
- Use subqueries excessively
- Query audit log tables
- Access PHI/PII without justification
Known Limitations
1. No Read-Only Database Connection
Current State: Reports execute with full database permissions (constrained by RLS). Recommendation: For production, create a read-only PostgreSQL role:2. No Query Result Caching
Current State: Every report execution re-runs the full query. Recommendation: Implement Redis caching for frequently-run reports:- Cache key:
report:${report_id}:${JSON.stringify(params)} - TTL: 1 hour (configurable per report)
- Invalidation: On report definition update
3. No Rate Limiting
Current State: No limit on number of reports a user can run. Recommendation: Implement rate limiting:- Max 10 reports per minute per user
- Max 100 reports per hour per organization
- Exponential backoff for repeated failures
Incident Response
SQL Injection Detected
-
Immediate Actions:
- Disable affected report
- Revoke user access if malicious
- Review audit logs for data exfiltration
-
Investigation:
- Extract all queries from
pf_report_executionsfor user - Check for unusual table access patterns
- Review RLS policy effectiveness
- Extract all queries from
-
Remediation:
- Patch vulnerability
- Force password reset for affected users
- Notify security team
Performance Degradation
-
Immediate Actions:
- Identify long-running queries in
pg_stat_activity - Kill queries exceeding timeout threshold
- Temporarily disable expensive reports
- Identify long-running queries in
-
Investigation:
- Analyze query plans (
EXPLAIN ANALYZE) - Check for missing indexes
- Review query complexity violations
- Analyze query plans (
-
Remediation:
- Add indexes to frequently-queried columns
- Reduce query complexity limits if needed
- Educate report authors on query optimization
Testing Checklist
- SQL injection prevention (see test cases below)
- Query complexity limits enforced
- Parameterized queries work correctly
- Audit logs capture all executions
- RLS policies prevent cross-org access
- Timeout enforced for long queries
- Row limit enforced
SQL Injection Test Cases
References
- OWASP SQL Injection Prevention Cheat Sheet
- PostgreSQL Security Best Practices
- Supabase RLS Documentation
Maintained by: Platform Security Team
Next Review: 2025-12-25