Security Overview
Security Overview
Section titled “Security Overview”ImageBot implements enterprise-grade security measures to protect user data, API access, and system integrity.
Authentication & Authorization
Section titled “Authentication & Authorization”User Authentication
Section titled “User Authentication”Password Security:
- Passwords hashed with
bcrypt(cost factor: 10) - Minimum password length: 8 characters
- No password complexity requirements (passphrase approach)
- Password reset via secure email tokens
// Password hashing (worker/index.ts)import bcrypt from 'bcryptjs';
async function hashPassword(password: string): Promise<string> { return await bcrypt.hash(password, 10);}
async function verifyPassword(password: string, hash: string): Promise<boolean> { return await bcrypt.compare(password, hash);}JWT Token Management
Section titled “JWT Token Management”Session Tokens:
- Algorithm:
HS256(HMAC-SHA256) - Expiration: 7 days
- Stored in
localStorage(considerhttpOnlycookies for enhanced security) - Automatic refresh on valid requests
// JWT generationimport jwt from '@tsndr/cloudflare-worker-jwt';
const token = await jwt.sign({ userId: user.id, email: user.email, exp: Math.floor(Date.now() / 1000) + (60 * 60 * 24 * 7) // 7 days}, env.JWT_SECRET);Security Considerations:
- Store
JWT_SECRETin Wrangler secrets (never in code) - Rotate secrets every 90 days
- Implement token revocation for logout
- Use short expiration for sensitive operations
API Key Authentication
Section titled “API Key Authentication”Key Generation:
- Format:
imgbot_live_+ 32-byte random hex - Scoped permissions:
generate,read,manage - Multiple keys per user
- Individual key revocation
Storage:
- Keys hashed with SHA-256 before storage
- Original key shown only once
- Database stores hash for verification
// API key validationconst apiKey = request.headers.get('Authorization')?.replace('Bearer ', '');const keyHash = crypto.subtle.digest('SHA-256', new TextEncoder().encode(apiKey));const validKey = await db.prepare('SELECT * FROM api_keys WHERE key_hash = ? AND is_active = 1') .bind(keyHash).first();Data Protection
Section titled “Data Protection”Data Isolation
Section titled “Data Isolation”User Data Separation:
- All queries filtered by
user_id - No cross-user data access
- Team collaboration uses explicit permissions
- API keys scoped to owning user
-- Example query patternSELECT * FROM imagesWHERE user_id = ? AND is_deleted = 0ORDER BY created_at DESC;Encryption
Section titled “Encryption”At Rest:
- Cloudflare D1 encrypts all data at rest (AES-256)
- R2 objects encrypted automatically
- Secrets encrypted via Wrangler
In Transit:
- All requests over HTTPS/TLS 1.2+
- Cloudflare Universal SSL
- HSTS enabled
Sensitive Data Handling
Section titled “Sensitive Data Handling”PII Protection:
- Email addresses stored in plaintext (required for auth)
- No collection of unnecessary personal data
- User deletion removes all associated data
Payment Data:
- Never store credit card numbers
- Stripe handles all payment processing
- Only store Stripe customer IDs and payment intent IDs
Input Validation
Section titled “Input Validation”SQL Injection Prevention
Section titled “SQL Injection Prevention”Parameterized Queries: All database queries use prepared statements with bound parameters:
// Safe queryconst user = await env.DB.prepare( 'SELECT * FROM users WHERE email = ?').bind(email).first();
// NEVER do this:// const user = await env.DB.prepare(`SELECT * FROM users WHERE email = '${email}'`).first();XSS Prevention
Section titled “XSS Prevention”Content Security Policy:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' cdn.tailwindcss.com; img-src 'self' data: https:">React Auto-Escaping:
- React automatically escapes user content
- Avoid
dangerouslySetInnerHTML - Sanitize markdown with DOMPurify if needed
CSRF Protection
Section titled “CSRF Protection”Token-Based:
- All state-changing requests require authentication
- API uses stateless JWT (no cookies)
- SameSite cookie attribute for session cookies
Rate Limiting
Section titled “Rate Limiting”API Rate Limits
Section titled “API Rate Limits”Per User:
- 100 requests/minute (standard)
- 500 requests/minute (pro)
- Custom limits for enterprise
Per IP:
- 1000 requests/hour (unauthenticated)
- Prevents brute force attacks
// Rate limit implementationconst rateLimitKey = `ratelimit:${userId}:${Math.floor(Date.now() / 60000)}`;const count = await env.CACHE.get(rateLimitKey);
if (parseInt(count || '0') > 100) { return new Response('Rate limit exceeded', { status: 429 });}
await env.CACHE.put(rateLimitKey, (parseInt(count || '0') + 1).toString(), { expirationTtl: 60 });Brute Force Protection
Section titled “Brute Force Protection”Login Attempts:
- Max 5 failed attempts per IP per hour
- Exponential backoff: 2^n seconds
- Account lockout after 10 failed attempts
- Email notification on suspicious activity
CORS Configuration
Section titled “CORS Configuration”Production Settings:
const corsHeaders = { 'Access-Control-Allow-Origin': 'https://app.yourdomain.com', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization', 'Access-Control-Max-Age': '86400',};Development:
'Access-Control-Allow-Origin': '*' // Only for local developmentSecret Management
Section titled “Secret Management”Environment Variables
Section titled “Environment Variables”Wrangler Secrets:
wrangler secret put JWT_SECRETwrangler secret put STRIPE_SECRET_KEYwrangler secret put GITHUB_CLIENT_SECRETNever commit:
- API keys
- Database credentials
- OAuth client secrets
- JWT signing keys
.gitignore Configuration
Section titled “.gitignore Configuration”.env.env.local.env.production.dev.varswrangler.toml.local*.pem*.keyMulti-Tenant Security
Section titled “Multi-Tenant Security”Team Isolation
Section titled “Team Isolation”Permission Checks:
// Verify team membership before accessasync function verifyTeamMembership(env: any, userId: string, teamId: string): Promise<boolean> { const member = await env.DB.prepare( 'SELECT * FROM team_members WHERE team_id = ? AND user_id = ? AND status = "active"' ).bind(teamId, userId).first();
return !!member;}Role-Based Access Control (RBAC)
Section titled “Role-Based Access Control (RBAC)”Roles:
owner: Full control, billing accessadmin: Manage members, settingsmember: Create, edit contentviewer: Read-only access
function hasPermission(role: string, action: string): boolean { const permissions = { owner: ['*'], admin: ['invite', 'manage_settings', 'edit', 'view'], member: ['edit', 'view', 'comment'], viewer: ['view'] };
return permissions[role]?.includes(action) || permissions[role]?.includes('*');}Security Headers
Section titled “Security Headers”HTTP Security Headers
Section titled “HTTP Security Headers”const securityHeaders = { 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'DENY', 'X-XSS-Protection': '1; mode=block', 'Referrer-Policy': 'strict-origin-when-cross-origin', 'Permissions-Policy': 'geolocation=(), microphone=(), camera=()', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload'};Audit Logging
Section titled “Audit Logging”User Activity Tracking
Section titled “User Activity Tracking”Logged Events:
- User registration
- Login/logout
- Password changes
- Image generation
- License purchases
- Team invitations
- API key creation/revocation
- Payment transactions
async function logAuditEvent(env: any, event: AuditEvent) { await env.DB.prepare(` INSERT INTO audit_log (user_id, event_type, metadata, ip_address, timestamp) VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP) `).bind(event.userId, event.type, JSON.stringify(event.metadata), event.ip).run();}Compliance
Section titled “Compliance”Data Retention:
- Audit logs: 1 year
- User data: Until account deletion
- Deleted images: 30-day soft delete period
Vulnerability Management
Section titled “Vulnerability Management”Dependency Scanning
Section titled “Dependency Scanning”# Run security auditnpm audit
# Fix vulnerabilitiesnpm audit fix
# Check for outdated packagesnpm outdatedAutomated Tools:
- Dependabot (GitHub) for dependency updates
- Snyk for vulnerability scanning
- OWASP Dependency-Check
Security Testing
Section titled “Security Testing”Recommended Tests:
- SQL Injection - Test all input fields with SQL payloads
- XSS - Test with
<script>alert('XSS')</script> - Authentication Bypass - Test API without tokens
- IDOR - Test accessing other users’ resources
- Rate Limiting - Verify throttling works
Incident Response
Section titled “Incident Response”Security Breach Protocol
Section titled “Security Breach Protocol”-
Detection
- Monitor error rates and unusual activity
- Alert on failed auth attempts spike
- Review audit logs daily
-
Containment
- Revoke compromised API keys immediately
- Force password reset for affected users
- Block suspicious IP addresses
-
Investigation
- Review audit logs for breach scope
- Identify attack vector
- Assess data exposure
-
Recovery
- Patch vulnerability
- Restore from backups if needed
- Deploy security fixes
-
Notification
- Notify affected users within 72 hours
- Report to authorities if required (GDPR)
- Public disclosure if widespread
Contact
Section titled “Contact”Security Issues:
- Email: security@imagebot.com
- PGP Key: [Public key link]
- Bug Bounty: [HackerOne/BugCrowd link]
Compliance & Regulations
Section titled “Compliance & Regulations”GDPR Compliance
Section titled “GDPR Compliance”User Rights:
- Right to access data
- Right to deletion
- Right to data portability
- Right to rectification
Implementation:
// Export user dataasync function exportUserData(env: any, userId: string) { const user = await getUserById(env, userId); const images = await getImagesByUser(env, userId); const collections = await getCollectionsByUser(env, userId);
return { user, images, collections, exported_at: new Date().toISOString() };}
// Delete user and all dataasync function deleteUser(env: any, userId: string) { await env.DB.batch([ env.DB.prepare('DELETE FROM images WHERE user_id = ?').bind(userId), env.DB.prepare('DELETE FROM collections WHERE user_id = ?').bind(userId), env.DB.prepare('DELETE FROM users WHERE id = ?').bind(userId) ]);}PCI DSS (Payment Card Industry)
Section titled “PCI DSS (Payment Card Industry)”- No card data stored in ImageBot
- All payments processed through Stripe (PCI Level 1)
- Use Stripe Elements for card input
- Webhook signature verification
Best Practices
Section titled “Best Practices”For Developers
Section titled “For Developers”- Never commit secrets - Use Wrangler secrets
- Use prepared statements - Prevent SQL injection
- Validate all input - Trust no user input
- Implement rate limiting - Prevent abuse
- Log security events - Enable audit trail
- Keep dependencies updated - Patch vulnerabilities
- Use HTTPS everywhere - No mixed content
For Users
Section titled “For Users”- Use strong passwords - 12+ characters, unique
- Enable 2FA - Additional security layer (if implemented)
- Review API keys - Revoke unused keys
- Monitor activity - Check audit logs
- Report suspicious activity - Contact security team
Security Roadmap
Section titled “Security Roadmap”Planned Features:
- Two-factor authentication (2FA)
- OAuth 2.0 with GitHub/Google
- IP whitelisting for API keys
- Advanced threat detection
- Automated security scanning
- Bug bounty program
- SOC 2 compliance