Please report security vulnerabilities to security@healthwatchers.com. Do not open public GitHub issues for security vulnerabilities.
We aim to respond within 48 hours and will coordinate a fix and disclosure timeline with you.
Clinic Stellar secret keys (starting with S) provide full control over a clinic's Stellar account. A single database breach without encryption would allow an attacker to drain all clinic funds.
Stellar secret keys are encrypted at rest using AES-256-GCM before storage in MongoDB. The implementation is in apps/api/src/modules/clinics/keypair.service.ts.
Key separation: The Stellar keypair encryption uses a dedicated KEYPAIR_ENCRYPTION_KEY environment variable — a separate 32-byte key from the PHI field encryption key (FIELD_ENCRYPTION_KEY). This ensures that compromising one key does not expose both PHI and Stellar secrets.
Storage format:
encryptedSecretKey:<ciphertext_hex>:<auth_tag_hex>— AES-256-GCM ciphertext with authentication tagiv:<iv_hex>— 16-byte random IV stored separately
Guarantees:
- Raw Stellar secret keys (starting with
S) are never stored in MongoDB - Each encryption uses a fresh random IV (no IV reuse)
- GCM authentication tag prevents ciphertext tampering
- Decryption failures are counted via the
mongodb_keypair_decryption_failures_totalPrometheus metric and trigger a critical alert
| Variable | Description | Required |
|---|---|---|
KEYPAIR_ENCRYPTION_KEY |
64-char hex string (32 bytes) for Stellar keypair encryption | Yes |
FIELD_ENCRYPTION_KEY |
64-char hex string (32 bytes) for PHI field encryption | Yes |
Generate a secure key:
openssl rand -hex 32To rotate the KEYPAIR_ENCRYPTION_KEY:
- Generate a new key:
openssl rand -hex 32 - Write a migration script that:
- Reads each
ClinicKeypairdocument - Decrypts
encryptedSecretKeywith the old key - Re-encrypts with the new key
- Updates the document and increments
keyVersion
- Reads each
- Deploy the migration before updating the environment variable
- Update
KEYPAIR_ENCRYPTION_KEYin your secrets manager (AWS Secrets Manager / HashiCorp Vault)
- AWS KMS / HashiCorp Vault: For production, consider wrapping the
KEYPAIR_ENCRYPTION_KEYwith a KMS-managed Key Encryption Key (KEK). This provides hardware-backed key protection and automatic key rotation. - Envelope encryption: Store only the encrypted data key in the database; the master key never leaves KMS.
Patient PHI fields (contactNumber, address, dateOfBirth) are encrypted at rest using AES-256-GCM via apps/api/src/lib/encrypt.ts. The encryption key is configured via FIELD_ENCRYPTION_KEY.
- JWT-based authentication with short-lived access tokens and rotating refresh tokens
- Role-based access control (SUPER_ADMIN, CLINIC_ADMIN, DOCTOR, NURSE, ASSISTANT, READ_ONLY)
- MFA support via TOTP
Security-relevant Prometheus alerts are defined in monitoring/alerts.yml:
StellarKeypairDecryptionFailure— fires immediately on any decryption failure (critical)MongoDBPoolHighUtilization— fires when pool utilization > 80% for 2 minutes (warning)MongoDBPoolWaitQueueNonEmpty— fires when requests queue for connections (critical)
Health Watchers is designed with HIPAA and GDPR compliance in mind. This document outlines security practices and guidelines.
- Authentication & Authorization
- Data Protection
- API Security
- Incident Response
- Compliance
- Reporting Security Issues
- Minimum 12 characters
- Must contain uppercase, lowercase, numbers, and special characters
- Passwords hashed with bcrypt (cost 12)
- Password reset tokens expire after 1 hour
- Account lockout after 5 failed login attempts (15 minutes)
- TOTP (Time-based One-Time Password) available for admin roles
- Backup codes generated during MFA setup
- MFA required for SUPER_ADMIN and CLINIC_ADMIN roles
- Access tokens expire after 15 minutes
- Refresh tokens expire after 7 days
- Refresh token rotation: new token issued on each refresh
- Tokens stored in secure HTTP-only cookies
- Token revocation on logout
Access tokens are short-lived (15 min) but can be explicitly invalidated before expiry:
- Per-token denylist: Each access token carries a
jti(UUID v4) claim. On logout or password change, thejtiis stored in Redis with a TTL equal to the token's remaining lifetime.verifyAccessTokenrejects any token whosejtiis in the denylist. - Logout-all:
POST /api/v1/auth/logout-allstores a per-user invalidation timestamp (user-invalidated:{userId}) in Redis. All access tokens with aniat(issued-at) before that timestamp are rejected, effectively invalidating every active session for the user. - Graceful degradation: If Redis is unavailable, denylist checks are skipped and tokens remain valid until natural expiry. This is acceptable given the 15-minute access token lifetime.
Redis keys used:
| Key pattern | Purpose | TTL |
|---|---|---|
token-denylist:{jti} |
Single-token revocation | Token's remaining lifetime |
user-invalidated:{userId} |
Logout-all timestamp | 7 days |
Roles and permissions:
| Role | Permissions |
|---|---|
| SUPER_ADMIN | Full system access |
| CLINIC_ADMIN | Clinic management, user management, billing |
| DOCTOR | Patient management, encounter creation, prescriptions |
| NURSE | Patient management, vital signs, basic documentation |
| ASSISTANT | Appointment scheduling, patient communication |
| READ_ONLY | View-only access to patient records |
| PATIENT | Access own records, appointments, payments |
- At Rest: AES-256-GCM encryption for sensitive data
- In Transit: TLS 1.2+ enforced, HTTPS only in production
- Database: MongoDB encryption at rest enabled
- Secrets: AWS Secrets Manager for API keys and private keys
- PHI (Protected Health Information) encrypted at rest
- Passwords never logged or transmitted in plain text
- Stellar private keys stored in secure enclave
- Credit card data: PCI-DSS compliant (tokenized via Stellar)
- Audit logs sanitized to exclude sensitive fields
- Patient records: Retained per HIPAA requirements (6 years minimum)
- Audit logs: Retained for 90 days
- Deleted data: Securely wiped using cryptographic erasure
- Right to be forgotten: Data export and deletion available
- All inputs validated with Zod schemas
- File uploads scanned for malware
- File size limits enforced (max 10MB)
- Allowed file types whitelist
- General endpoints: 100 requests per 15 minutes per IP
- Authentication endpoints: 5 attempts per 15 minutes per IP
- Payment endpoints: 10 requests per 15 minutes per user
- Whitelist specific origins (not *)
- Credentials allowed only for trusted origins
- Preflight requests validated
- Content-Security-Policy (CSP)
- X-Frame-Options: DENY
- X-Content-Type-Options: nosniff
- Strict-Transport-Security (HSTS)
- X-XSS-Protection
- Parameterized queries via Mongoose
- Input sanitization for regex patterns
- No eval() or Function() with user input
If you discover a security vulnerability:
-
Do not publicly disclose the vulnerability
-
Email security@healthwatchers.com with:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Your contact information
-
We will:
- Acknowledge receipt within 24 hours
- Investigate and assess severity
- Develop and test a fix
- Release a patch and security advisory
- Credit the reporter (if desired)
- Security incidents logged and tracked
- Incident severity assessed (Critical, High, Medium, Low)
- Affected users notified within 24 hours for Critical/High
- Root cause analysis performed
- Preventive measures implemented
- Business Associate Agreement (BAA) in place
- PHI encryption at rest and in transit
- Access controls and audit logging
- Breach notification procedures
- Annual security risk assessment
- Data processing agreements in place
- Data retention policies enforced
- Right to access, rectification, erasure
- Data portability (export functionality)
- Privacy policy and consent management
- Credit card data tokenized via Stellar
- No credit card storage on servers
- Secure payment processing
- Regular security assessments
- Code Review: All code reviewed by at least one other developer
- Dependency Management: Keep dependencies up to date, use
npm audit - Secrets Management: Never commit secrets, use environment variables
- Logging: Log security events, but never log sensitive data
- Testing: Write security tests for authentication and authorization
- Access Control: Principle of least privilege
- Monitoring: Monitor logs for suspicious activity
- Backups: Regular encrypted backups, test restore procedures
- Updates: Apply security patches promptly
- Audits: Regular security audits and penetration testing
- Strong Passwords: Use unique, strong passwords
- MFA: Enable multi-factor authentication
- Phishing: Be cautious of suspicious emails
- Reporting: Report suspicious activity immediately
See SECURITY_CHECKLIST.md for detailed OWASP Top 10 assessment and penetration testing checklist.
| Version | Date | Changes |
|---|---|---|
| 1.0 | 2026-05-27 | Initial security guidelines |
Last Updated: 2026-05-27
Next Review: 2026-08-27