Security Incident Response - jra3/mulm GitHub Wiki
Security Incident Response
This guide provides procedures for responding to security incidents in the Mulm platform.
Overview
A security incident is any event that compromises the confidentiality, integrity, or availability of the system or user data.
Response Team:
- System Administrator
- Project Maintainer
- Club Leadership (as needed)
Response Time:
- Critical incidents: Immediate response (within 1 hour)
- High severity: Response within 4 hours
- Medium severity: Response within 24 hours
- Low severity: Response within 1 week
Table of Contents
Incident Classification
Severity Levels
| Severity | Definition | Examples | Response Time |
|---|---|---|---|
| Critical | Active attack, data breach, complete service outage | SQL injection exploit, database leaked, site completely down | Immediate (< 1 hour) |
| High | Vulnerability discovered, partial outage, unauthorized access | XSS vulnerability found, admin account compromised | < 4 hours |
| Medium | Security weakness, degraded service, suspicious activity | Weak password policy, rate limiting bypass, unusual traffic | < 24 hours |
| Low | Minor security concern, no immediate risk | Outdated dependency, information disclosure in logs | < 1 week |
Incident Types
Security Incidents:
- Unauthorized access
- Data breach or exposure
- SQL injection exploit
- XSS attack
- CSRF attack
- Session hijacking
- DDoS attack
- Malware/ransomware
Availability Incidents:
- Complete service outage
- Database corruption
- Server compromise
- Infrastructure failure
Data Integrity Incidents:
- Database modification by unauthorized party
- Data corruption
- Accidental data deletion
Response Procedures
Phase 1: Detection & Assessment
1. Detect incident:
- Automated monitoring alert
- User report
- Security researcher disclosure
- Admin discovers during routine check
2. Initial assessment:
- Confirm incident is real (not false positive)
- Classify severity level
- Identify affected systems
- Determine if ongoing or contained
3. Document:
- Create incident ticket (private GitHub issue or separate system)
- Record detection time, detector, initial findings
Phase 2: Containment
Immediate actions (within 1 hour for critical):
For active attack:
# 1. Block attacking IP at nginx level
ssh BAP "sudo docker exec basny-nginx sh -c 'echo \"deny 1.2.3.4;\" >> /etc/nginx/conf.d/blocked-ips.conf'"
ssh BAP "sudo docker exec basny-nginx nginx -s reload"
# 2. Take site offline if needed (critical only)
ssh BAP "cd /opt/basny && sudo docker-compose -f docker-compose.prod.yml down"
# 3. Create database snapshot
aws --profile basny ec2 create-snapshot \
--volume-id vol-0aba5b85a1582b2c0 \
--description "Emergency snapshot - security incident $(date +%Y%m%d-%H%M%S)"
For vulnerability discovered:
# 1. Assess if being actively exploited
ssh BAP "sudo docker logs basny-app | grep -i 'suspicious-pattern'"
# 2. If not exploited, plan fix
# 3. If exploited, follow active attack procedures
For compromised credentials:
# 1. Revoke compromised credentials immediately
# - Rotate API keys (R2, OAuth, SMTP)
# - Reset admin passwords
# - Invalidate all sessions
# 2. Update credentials
ssh BAP "sudo vi /mnt/basny-data/app/config/config.production.json"
# 3. Restart app
ssh BAP "cd /opt/basny && sudo docker-compose -f docker-compose.prod.yml restart app"
Phase 3: Eradication
Fix the vulnerability:
# 1. Develop fix
# - Create patch
# - Write tests
# - Verify fix works
# 2. Deploy fix
ssh BAP "cd /opt/basny && git pull && sudo docker-compose -f docker-compose.prod.yml up -d --build"
# 3. Verify fix deployed
curl https://bap.basny.org/health
# 4. Test vulnerability is fixed
# - Attempt exploit (safely)
# - Verify it no longer works
Phase 4: Recovery
Restore normal operations:
# 1. Bring site back online (if taken down)
ssh BAP "cd /opt/basny && sudo docker-compose -f docker-compose.prod.yml up -d"
# 2. Monitor closely
ssh BAP "sudo docker logs basny-app -f"
# 3. Verify all functionality works
# - Test login
# - Test submissions
# - Test admin features
# 4. Check for data integrity
ssh BAP "sqlite3 /mnt/basny-data/app/database/database.db 'PRAGMA integrity_check;'"
Phase 5: Communication
Who to notify:
| Audience | When | What to Say |
|---|---|---|
| Users | If data breach or extended downtime | Brief explanation, what we're doing, what they should do |
| Admins | For any security incident | Full details, actions taken, next steps |
| Security Researcher | If they reported it | Thank you, timeline for fix, credit offer |
| Authorities | If required by law (data breach) | As legally required |
Example user notification:
Subject: BASNY BAP Security Update
On October 7, 2025, we discovered a security issue that may have
exposed member email addresses. We have:
✅ Fixed the vulnerability
✅ Verified no passwords were exposed
✅ Reset all active sessions as a precaution
What you should do:
- Log in again (your session was reset)
- Consider changing your password (optional, but recommended)
- Watch for phishing emails (we will never ask for your password)
We take security seriously and apologize for any concern this may cause.
If you have questions, please contact [email protected]
- BASNY BAP Team
Incident Types
SQL Injection Exploit
Detection:
- Unusual database queries in logs
- Unexpected data modifications
- Error messages about SQL syntax
Response:
# 1. IMMEDIATE: Block attacking IP
ssh BAP "sudo docker exec basny-nginx sh -c 'echo \"deny ATTACKER_IP;\" >> /etc/nginx/conf.d/blocked-ips.conf'"
ssh BAP "sudo docker exec basny-nginx nginx -s reload"
# 2. Take snapshot
aws --profile basny ec2 create-snapshot --volume-id vol-0aba5b85a1582b2c0 --description "Pre-recovery snapshot"
# 3. Analyze attack
ssh BAP "sudo docker logs basny-app | grep 'ATTACKER_IP'"
# 4. Fix vulnerable code (use prepared statements)
# 5. Check for data tampering
ssh BAP "sqlite3 /mnt/basny-data/app/database/database.db 'SELECT * FROM members WHERE is_admin=1;'"
# Verify all admins are legitimate
# 6. Restore from backup if data was modified
# See Backup-Recovery guide
Data Breach
Detection:
- Database file accessed by unauthorized party
- Configuration file with secrets exposed
- User reports receiving spam to unique email
Response:
# 1. CRITICAL: Determine what was exposed
# - Passwords? (hashed with scrypt - should be safe)
# - Emails? (notify users)
# - API keys? (rotate immediately)
# - Database file? (contains all above)
# 2. Rotate all secrets
# - R2 keys
# - OAuth secrets
# - SMTP password
# - Session secret
# 3. Invalidate all sessions
ssh BAP "sqlite3 /mnt/basny-data/app/database/database.db 'DELETE FROM sessions;'"
# 4. Force password reset for all users (if passwords may be compromised)
# - Send email with reset link to all members
# 5. Notify users
# - Email all members
# - Explain what happened
# - What data was exposed
# - What they should do
Compromised Admin Account
Detection:
- Admin actions by user who claims they didn't do them
- Suspicious admin actions in logs
- Admin reports unauthorized access
Response:
# 1. IMMEDIATE: Disable account
ssh BAP "sqlite3 /mnt/basny-data/app/database/database.db \"UPDATE members SET is_admin=0 WHERE id=ADMIN_ID;\""
# 2. Delete all sessions for that admin
ssh BAP "sqlite3 /mnt/basny-data/app/database/database.db \"DELETE FROM sessions WHERE member_id=ADMIN_ID;\""
# 3. Review recent admin actions
ssh BAP "sqlite3 /mnt/basny-data/app/database/database.db \"
SELECT * FROM submissions
WHERE approved_by=ADMIN_ID
AND approved_on > datetime('now', '-7 days')
ORDER BY approved_on DESC;
\""
# 4. Check for malicious approvals or data changes
# 5. Reset admin password
# 6. Re-enable admin status after verification
# 7. Enable 2FA (if implemented)
DDoS Attack
Detection:
- Extremely high traffic
- Site slow or unresponsive
- Rate limiter logs show excessive blocks
Response:
# 1. Check traffic sources
ssh BAP "sudo docker exec basny-nginx tail -1000 /var/log/nginx/access.log | awk '{print \$1}' | sort | uniq -c | sort -rn | head -20"
# 2. Block top offending IPs
ssh BAP "sudo docker exec basny-nginx sh -c 'echo \"deny 1.2.3.4;\" >> /etc/nginx/conf.d/blocked-ips.conf'"
ssh BAP "sudo docker exec basny-nginx nginx -s reload"
# 3. Enable Cloudflare (if not already)
# - Update DNS to point to Cloudflare
# - Enable "Under Attack Mode"
# 4. Lower rate limits temporarily
# Edit nginx.conf: rate=5r/s instead of 10r/s
# 5. Contact AWS support if attack is severe
Malware/Ransomware
Detection:
- Files encrypted
- Ransom note appears
- Unusual file modifications
Response:
# 1. IMMEDIATELY disconnect from network
ssh BAP "sudo shutdown -h now"
# 2. DO NOT pay ransom
# 3. Recover from backups
# - Restore from EBS snapshot
# - See Backup-Recovery guide
# 4. Analyze how infection occurred
# - Review SSH access logs
# - Check for unauthorized users
# - Scan for backdoors
# 5. Rebuild from known-good state if necessary
Post-Incident Review
Within 1 Week After Resolution
Conduct post-mortem meeting:
-
Timeline review
- When was incident detected?
- How long to contain?
- How long to fully resolve?
-
Root cause analysis
- What caused the incident?
- Why wasn't it prevented?
- What gaps exist in security?
-
Response effectiveness
- What went well?
- What went poorly?
- What should we improve?
-
Action items
- Specific improvements to implement
- Assign owners and deadlines
- Update this playbook
Post-Incident Report Template
# Security Incident Report - [Date]
## Incident Summary
- **Date/Time:** October 7, 2025 14:30 UTC
- **Severity:** High
- **Type:** SQL Injection Attempt
- **Status:** Resolved
## Timeline
- 14:30 - Incident detected (error in logs)
- 14:35 - Confirmed as SQL injection attempt
- 14:40 - Blocked attacking IP
- 14:45 - Analyzed attack vector
- 15:00 - Deployed fix
- 15:30 - Verified fix works
- 16:00 - Monitoring resumed
## Impact
- No data was compromised (prepared statements prevented injection)
- No user impact (attack blocked)
- 30 minutes heightened monitoring
## Root Cause
- User-submitted search query not properly validated
- Query used prepared statements (safe), but should also validate input
## Response Actions
1. Blocked attacking IP: 1.2.3.4
2. Added input validation for search endpoint
3. Added test case for malicious input
4. Reviewed all other endpoints for similar issues
## Lessons Learned
- ✅ Prepared statements worked as designed (no injection)
- ✅ Monitoring detected attack quickly
- ⚠️ Input validation should be layered (not just SQL-safe)
## Follow-Up Actions
- [ ] Add input validation to all search endpoints
- [ ] Implement automated security scanning (SQLMap)
- [ ] Add rate limiting to search endpoints
- [ ] Update security documentation
## Recommendations
- All endpoints should validate input with Zod schemas
- Security scanning should run on every PR
- Consider Web Application Firewall (WAF)
Prevention
Proactive Measures
Regular security reviews:
- Monthly dependency updates (
npm audit) - Quarterly penetration testing
- Annual security audit
- Continuous monitoring
Security scanning:
# Check for known vulnerabilities
npm audit
# Check for secrets in code
git secrets --scan
# Static analysis
npm run lint
Training:
- All contributors read Security Best Practices
- New admins trained on secure practices
- Annual security refresher
Emergency Contacts
Internal
| Role | Contact | Responsibility |
|---|---|---|
| System Administrator | [Contact info] | Infrastructure, deployment, access |
| Project Maintainer | [Contact info] | Code, security fixes |
| Club President | [Contact info] | User communication, decisions |
External
| Service | Contact | Purpose |
|---|---|---|
| AWS Support | Via AWS Console | Infrastructure issues |
| Cloudflare Support | Via dashboard | R2 storage, DDoS protection |
| Google OAuth | [email protected] | OAuth issues |
Recovery Procedures
Quick Recovery Checklist
For most incidents:
- Take snapshot of current state
- Analyze scope of incident
- Contain the incident
- Fix the vulnerability
- Deploy the fix
- Verify fix works
- Monitor for recurrence
- Document in incident report
- Communicate to affected parties
- Conduct post-mortem
Rollback Procedure
If recent deployment caused incident:
# 1. Check recent commits
ssh BAP "cd /opt/basny && git log --oneline -10"
# 2. Rollback to previous commit
ssh BAP "cd /opt/basny && git reset --hard HEAD~1"
# 3. Rebuild
ssh BAP "cd /opt/basny && sudo docker-compose -f docker-compose.prod.yml up -d --build"
# 4. Verify rollback fixed issue
curl https://bap.basny.org/health
Data Recovery
See: Backup & Recovery Guide for detailed procedures.
Legal Considerations
Data Breach Notification Laws
If personal data is compromised:
GDPR (if EU users):
- Must notify supervisory authority within 72 hours
- Must notify affected users "without undue delay"
US State Laws (vary by state):
- Check requirements for New York (BASNY location)
- May require notification to affected residents
Consult legal counsel if:
- More than 500 users affected
- Sensitive data exposed (SSN, payment info)
- Cross-border data breach
Documentation Requirements
Keep records of:
- When breach was discovered
- What data was affected
- How many users affected
- What actions were taken
- When users were notified
Testing Incident Response
Annual Security Drill
Simulate incident to test procedures:
-
Plan drill scenario
- Choose incident type (e.g., "SQL injection attempt")
- Define scope and constraints
- Schedule with team
-
Execute drill
- Run through response procedures
- Time each phase
- Document gaps or confusion
-
Review results
- What worked well?
- What needs improvement?
- Update procedures
-
Improve
- Update this playbook
- Add missing tools
- Train team on improvements
Related Documentation
- Security Overview - Current security posture
- Security Best Practices - Prevention guidelines
- Backup & Recovery - Recovery procedures
- Monitoring & Logs - Detection and analysis
- Production Deployment - Deployment procedures
Remember: Preparation is key. Review this guide periodically and conduct drills.
**Last Updated: November 2025