betting-brain-v3 / rules
brendadeeznuts1111/betting-brain-v3/.cursor/rules/security-patterns.mdc
Security patterns and vulnerability prevention
Cursor rule8 starsChanged 12 months ago
- Reads credentials
---
version: "2.0.0"
globs: "src/**/*.ts,scripts/**/*.ts"
alwaysApply: true
description: "Security patterns and vulnerability prevention"
lastUpdated: "2025-10-08"
dependencies: ["quality-standards", "api-patterns", "bun-runtime", "database-patterns"]
---
# Security Patterns
## 🔍 Code Searchability Patterns
### Find security-patterns Issues with ast-grep
```bash
# Find parseFloat($$$)
# Find env.$DB.prepare(`SELECT $QUERY`)
# Find new Date()
# Find WASM.*exports
ast-grep --pattern 'parseFloat($$$)' src/
ast-grep --pattern 'env.$DB.prepare(`SELECT $QUERY`)' src/
ast-grep --pattern 'new Date()' src/
ast-grep --pattern 'WASM.*exports' src/
sg -p 'parseFloat($$$)' src/
sg -p 'env.$DB.prepare(`SELECT' src/
sg -p 'new' src/
sg -p 'WASM.*exports' src/
```
### security-patterns Discovery Commands
```bash
sg search "parseFloat" src/
sg search "SELECT" src/
sg search "new Date()" src/
sg search "WASM" src/
```
### Search Examples
```bash
# Find parseFloat usage (security risk)
sg search 'parseFloat($$$)' src/
# Find SQL injection risks
sg search 'env.$DB.prepare(`SELECT' src/
# Find timezone issues
sg search 'new' src/
# Find WASM memory leaks
sg search 'WASM.*exports' src/
```
## Input Validation
### Parameter Validation
```typescript
// ✅ CORRECT: Validate all inputs
function validateInput(input: unknown): boolean {
if (typeof input !== 'string') return false;
if (input.length === 0) return false;
if (input.length > 1000) return false;
return true;
}
// ❌ WRONG: No validation
function processInput(input: unknown) {
// Direct use without validation
return input.toString();
}
```
### SQL Injection Prevention
```typescript
// ✅ CORRECT: Parameterized queries
const result = await env.ANALYTICS.prepare(`
SELECT * FROM users WHERE id = ? AND status = ?
`).bind(userId, status).all();
// ❌ WRONG: String interpolation
const result = await env.ANALYTICS.prepare(`
SELECT * FROM users WHERE id = '${userId}' AND status = '${status}'
`).all();
```
### XSS Prevention
```typescript
// ✅ CORRECT: Sanitize output
function sanitizeOutput(input: string): string {
return input
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// ❌ WRONG: Direct output
function displayUserInput(input: string) {
return `<div>${input}</div>`; // XSS risk
}
```
## Authentication & Authorization
### Token Validation
```typescript
// ✅ CORRECT: Validate JWT tokens
async function validateToken(token: string): Promise<boolean> {
try {
const payload = await Bun.jwt.verify(token, secret);
return payload.exp > Date.now() / 1000;
} catch (error) {
console.error('Token validation failed:', error);
return false;
}
}
// ❌ WRONG: No token validation
function processRequest(token: string) {
// Direct use without validation
return { user: 'authenticated' };
}
```
### Rate Limiting
```typescript
// ✅ CORRECT: Implement rate limiting
const rateLimits = new Map<string, number>();
function checkRateLimit(ip: string): boolean {
const now = Date.now();
const lastRequest = rateLimits.get(ip);
if (!lastRequest || now - lastRequest > 1000) {
rateLimits.set(ip, now);
return true;
}
return false;
}
// ❌ WRONG: No rate limiting
function handleRequest(request: Request) {
// Process without rate limiting
return processRequest(request);
}
```
## Data Protection
### Sensitive Data Handling
```typescript
// ✅ CORRECT: Hash sensitive data
async function hashPassword(password: string): Promise<string> {
return await Bun.password.hash(password, {
algorithm: 'bcrypt',
cost: 12
});
}
// ❌ WRONG: Store plain text
function storePassword(password: string) {
// Never store plain text passwords
return password;
}
```
### Data Encryption
```typescript
// ✅ CORRECT: Encrypt sensitive data
async function encryptData(data: string): Promise<string> {
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
const iv = crypto.getRandomValues(new Uint8Array(12));
const encrypted = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
key,
new TextEncoder().encode(data)
);
return btoa(String.fromCharCode(...new Uint8Array(encrypted)));
}
```
## Error Handling
### Secure Error Messages
```typescript
// ✅ CORRECT: Generic error messages with structured logging
import { createLogger } from '../utils/logger';
import { generateRequestId, createErrorResponse } from '../utils/request';
function handleError(error: Error, request: Request): Response {
const requestId = generateRequestId();
const logger = createLogger(request);
// Log internally with full details
logger.error('internal_error', {
requestId,
errorType: error.name
}, error);
// Return generic message to user
return createErrorResponse(
'Internal Server Error',
500,
'INTERNAL_ERROR',
requestId
);
}
// ❌ WRONG: Expose internal details
function handleError(error: Error): Response {
return new Response(JSON.stringify({
error: error.message,
stack: error.stack, // Never expose stack traces!
details: error.toString()
}), { status: 500 });
}
```
### Logging Security
```typescript
// ✅ CORRECT: Sanitize logs with structured logging
import { createLogger } from '../utils/logger';
function logRequest(request: Request, data: any) {
const logger = createLogger(request);
const sanitizedData = {
...data,
password: '[REDACTED]',
token: '[REDACTED]',
apiKey: '[REDACTED]',
secret: '[REDACTED]'
};
logger.info('request_logged', { data: sanitizedData });
}
// ❌ WRONG: Log sensitive data
function logRequest(request: Request, data: any) {
console.log('Request data:', data); // May contain sensitive info!
}
```
## CORS Security
### CORS Configuration
```typescript
// ✅ CORRECT: Restrictive CORS
const corsHeaders = {
'Access-Control-Allow-Origin': 'https://trusted-domain.com',
'Access-Control-Allow-Methods': 'GET, POST',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400'
};
// ❌ WRONG: Overly permissive CORS
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': '*',
'Access-Control-Allow-Headers': '*'
};
```
## Environment Security
### Environment Variables
```typescript
// ✅ CORRECT: Validate environment variables
function validateEnv(env: Env): boolean {
const required = ['ANALYTICS', 'SECRET_KEY', 'API_URL'];
for (const key of required) {
if (!env[key]) {
throw new Error(`Missing required environment variable: ${key}`);
}
}
return true;
}
// ❌ WRONG: Use without validation
function processRequest(env: Env) {
// Direct use without checking if variables exist
return env.SECRET_KEY;
}
```
### Secret Management
```typescript
// ✅ CORRECT: Use environment for secrets
const secretKey = env.SECRET_KEY;
if (!secretKey) {
throw new Error('SECRET_KEY not configured');
}
// ❌ WRONG: Hardcode secrets
const secretKey = 'hardcoded-secret-key'; // Never do this
```
## File Security
### File Upload Validation
```typescript
// ✅ CORRECT: Validate file uploads
function validateFile(file: File): boolean {
const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
const maxSize = 5 * 1024 * 1024; // 5MB
if (!allowedTypes.includes(file.type)) {
return false;
}
if (file.size > maxSize) {
return false;
}
return true;
}
```
### Path Traversal Prevention
```typescript
// ✅ CORRECT: Validate file paths
function validateFilePath(path: string): boolean {
const normalizedPath = path.normalize(path);
return !normalizedPath.includes('..') &&
!normalizedPath.startsWith('/') &&
normalizedPath.length < 100;
}
// ❌ WRONG: Direct path usage
function readFile(path: string) {
// No validation - path traversal risk
return Bun.file(path);
}
```
## Security Headers
### Response Headers
```typescript
// ✅ CORRECT: Security headers
const securityHeaders = {
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'X-XSS-Protection': '1; mode=block',
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
'Content-Security-Policy': "default-src 'self'"
};
return new Response(data, {
headers: { ...securityHeaders, ...corsHeaders }
});
```
## Key Files
- [Security Rules](mdc:rules/) - ast-grep security rules
- [Production Security](mdc:.cursor/rules/production-security.mdc) - Production security patterns
- [Error Handler](mdc:src/utils/error-handler.ts) - Error handling patterns
- [Validation](mdc:src/utils/validation.ts) - Input validation
## Rules Summary
1. ✅ **Always** validate all inputs
2. ✅ **Always** use parameterized queries
3. ✅ **Always** sanitize output
4. ✅ **Always** validate tokens
5. ✅ **Always** implement rate limiting
6. ✅ **Always** hash sensitive data
7. ✅ **Always** use secure error messages
8. ✅ **Always** sanitize logs with StructuredLogger ⭐ **UPDATED**
9. ✅ **Always** use restrictive CORS
10. ✅ **Always** validate environment variables
11. ❌ **Never** expose internal details
12. ❌ **Never** hardcode secrets
13. ❌ **Never** use string interpolation in SQL
14. ❌ **Never** ignore security headers
15. ❌ **Never** use console.log (use StructuredLogger) ⭐ **NEW**
---
## Related Rules
- [Quality Standards](mdc:.cursor/rules/quality-standards.mdc) - Code quality standards ⭐ **NEW**
- [API Patterns](mdc:.cursor/rules/api-patterns.mdc) - API design patterns
- [Database Patterns](mdc:.cursor/rules/database-patterns.mdc) - SQL injection prevention
- [Production Security](mdc:.cursor/rules/production-security.mdc) - Production security patterns
## Related Documentation
- [docs/QUALITY_STANDARDS.md](mdc:docs/QUALITY_STANDARDS.md) - Complete quality guide ⭐ **NEW**
- [src/utils/logger.ts](mdc:src/utils/logger.ts) - Secure logging utilities ⭐ **NEW**
- [src/utils/request.ts](mdc:src/utils/request.ts) - Request utilities ⭐ **NEW**
- [src/utils/error-handler.ts](mdc:src/utils/error-handler.ts) - Error handling patterns
- [src/utils/validation.ts](mdc:src/utils/validation.ts) - Input validation
- [rules/](mdc:rules/) - ast-grep security rules
---
**Status:** Security patterns established
**Last Updated:** 2025-10-08Discussion
Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.
Posts are public.Sign in to post
No one has posted yet. Be the first.

