fix(security): Resolve 21 SQL injection vulnerabilities and add transactions
Security fixes (v1.2.2): - Fix SQL injection in analytics.ts (16 occurrences) - Fix SQL injection in advanced-search.ts (1 occurrence) - Fix SQL injection in search-queries.ts (1 occurrence) - Add validateDaysInterval(), isValidISODate(), validatePeriod() to security.ts - Use make_interval(days => N) for safe PostgreSQL intervals - Validate UUIDs BEFORE string construction Transaction support: - bulk-operations.ts: 6 atomic operations with withTransaction() - desk-sync.ts: 2 operations with transactions - export-import.ts: 1 operation with transaction Rate limiting: - Add automatic cleanup of expired entries (every 5 minutes) Audit: - Archive previous audit docs to docs/audits/2026-01-31-v1.2.1/ - Create new AUDIT-REQUEST.md for v1.2.2 verification Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -113,3 +113,50 @@ export function validateSortField(field: string | undefined, allowedFields: stri
|
||||
if (!field) return defaultField;
|
||||
return allowedFields.includes(field) ? field : defaultField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate and sanitize days interval for SQL INTERVAL
|
||||
* Prevents SQL injection by ensuring the value is a safe integer
|
||||
*/
|
||||
export function validateDaysInterval(days: unknown, defaultDays = 30, maxDays = 365): number {
|
||||
const parsed = parseInt(String(days), 10);
|
||||
if (isNaN(parsed) || parsed < 1) return defaultDays;
|
||||
return Math.min(parsed, maxDays);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate ISO date format
|
||||
* Accepts: YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss(.sss)?Z?
|
||||
*/
|
||||
export function isValidISODate(date: string): boolean {
|
||||
const isoRegex = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?)?$/;
|
||||
if (!isoRegex.test(date)) return false;
|
||||
const d = new Date(date);
|
||||
return !isNaN(d.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate period parameter against allowed values
|
||||
*/
|
||||
export function validatePeriod(period: string | undefined, allowedPeriods: string[], defaultPeriod: string): string {
|
||||
if (!period) return defaultPeriod;
|
||||
return allowedPeriods.includes(period) ? period : defaultPeriod;
|
||||
}
|
||||
|
||||
// Rate limit store cleanup interval (5 minutes)
|
||||
const RATE_LIMIT_CLEANUP_INTERVAL = 300000;
|
||||
|
||||
/**
|
||||
* Clean up expired rate limit entries
|
||||
*/
|
||||
function cleanupRateLimitStore(): void {
|
||||
const now = Date.now();
|
||||
for (const [key, entry] of rateLimitStore.entries()) {
|
||||
if (now > entry.resetAt) {
|
||||
rateLimitStore.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start cleanup interval
|
||||
setInterval(cleanupRateLimitStore, RATE_LIMIT_CLEANUP_INTERVAL);
|
||||
|
||||
Reference in New Issue
Block a user