Time-Based Business Logic Vulnerabilities and Temporal Manipulation Attacks

High Risk Business Logic
time-manipulationtemporal-attackstimezone-confusionscheduling-vulnerabilitiestimestamp-tamperingbusiness-logictiming-attacks

What it is

A high-severity vulnerability where applications that rely on time-based business logic can be exploited through timestamp manipulation, timezone confusion, scheduling system abuse, or temporal race conditions. These attacks can lead to bypassing time-based restrictions, unauthorized access to time-sensitive features, financial fraud through timing manipulation, and circumvention of rate limiting or access controls.

// VULNERABLE: Time-based system with client timestamp trust app.post('/api/schedule-payment', async (req, res) => { const { amount, recipientId, scheduledTime } = req.body; try { // PROBLEM: Trusting client-provided timestamp const scheduledDate = new Date(scheduledTime); if (scheduledDate < new Date()) { return res.status(400).json({ error: 'Cannot schedule in past' }); } const payment = await ScheduledPayment.create({ userId: req.user.id, amount, recipientId, scheduledTime: scheduledDate, status: 'scheduled' }); res.json({ success: true, paymentId: payment.id }); } catch (error) { res.status(500).json({ error: 'Scheduling failed' }); } });
// SECURE: Server-authoritative time-based business logic const { body, validationResult } = require('express-validator'); const moment = require('moment-timezone'); app.post('/api/schedule-payment', [ body('amount').isFloat({ min: 0.01 }).withMessage('Valid amount required'), body('recipientId').isUUID().withMessage('Valid recipient ID required'), body('scheduledTime').isISO8601().withMessage('Valid ISO8601 timestamp required'), body('timezone').optional().isString().withMessage('Valid timezone required'), body('idempotencyKey').optional().isUUID().withMessage('Valid idempotency key required') ], async (req, res) => { try { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); } const { amount, recipientId, scheduledTime, timezone, idempotencyKey } = req.body; // Initialize secure time authority const timeAuthority = new SecureTimeAuthority(); const schedulingSystem = new SecureSchedulingSystem(); // Validate client timestamp against server time const timeValidation = timeAuthority.validateClientTimestamp( scheduledTime, 30000 // 30 second allowable skew ); if (!timeValidation.isValid) { return res.status(400).json({ error: 'Invalid timestamp', serverTime: timeAuthority.getServerTime(), clientTime: scheduledTime, skew: timeValidation.skew }); } // Validate and normalize timezone const validTimezone = await timeAuthority.validateTimezone( timezone || 'UTC' ); // Convert to server time for processing const serverScheduledTime = moment.tz(scheduledTime, validTimezone).utc(); const serverCurrentTime = moment.utc(); // Validate scheduling window with server authority const minAdvance = moment.duration(5, 'minutes'); const maxAdvance = moment.duration(90, 'days'); if (serverScheduledTime.isBefore(serverCurrentTime.clone().add(minAdvance))) { return res.status(400).json({ error: 'Payment must be scheduled at least 5 minutes in advance', minimumScheduleTime: serverCurrentTime.clone().add(minAdvance).toISOString(), requestedTime: serverScheduledTime.toISOString() }); } if (serverScheduledTime.isAfter(serverCurrentTime.clone().add(maxAdvance))) { return res.status(400).json({ error: 'Payment cannot be scheduled more than 90 days in advance', maximumScheduleTime: serverCurrentTime.clone().add(maxAdvance).toISOString(), requestedTime: serverScheduledTime.toISOString() }); } // Validate operation time window const timeWindowValidation = await timeAuthority.validateTimeWindow( 'payment_processing', validTimezone ); if (!timeWindowValidation.allowed) { return res.status(400).json({ error: 'Payment processing not allowed at scheduled time', reason: timeWindowValidation.reason, businessHours: timeWindowValidation.businessHours, businessTimezone: timeWindowValidation.businessTimezone }); } // Check for duplicate scheduling using idempotency if (idempotencyKey) { const existingPayment = await ScheduledPayment.findOne({ idempotencyKey, status: { $in: ['scheduled', 'processing'] } }); if (existingPayment) { return res.json({ success: true, paymentId: existingPayment.id, scheduledTime: existingPayment.scheduledTime, isIdempotent: true }); } } // Validate recipient and user permissions const recipient = await User.findById(recipientId); if (!recipient) { return res.status(404).json({ error: 'Recipient not found' }); } const user = await User.findById(req.user.id).populate('account'); if (user.account.balance < amount) { return res.status(400).json({ error: 'Insufficient funds', availableBalance: user.account.balance, requestedAmount: amount }); } // Create scheduled payment with server-authoritative data const secureTimestamp = timeAuthority.generateSecureTimestamp( `payment:${req.user.id}:${recipientId}` ); const scheduledPayment = await ScheduledPayment.create({ paymentId: secureTimestamp.hash, userId: req.user.id, recipientId, amount: parseFloat(amount), scheduledTime: serverScheduledTime.toDate(), originalTimezone: validTimezone, status: 'scheduled', idempotencyKey, createdAt: new Date(), securityHash: secureTimestamp.hash, timeValidation: { clientTime: scheduledTime, serverTime: serverCurrentTime.toISOString(), skew: timeValidation.skew } }); // Schedule processing job with server time await schedulePaymentProcessing(scheduledPayment.id, serverScheduledTime.toDate()); // Log scheduling event await SecurityLog.create({ type: 'payment_scheduled', userId: req.user.id, details: { paymentId: scheduledPayment.id, amount, recipientId, scheduledTime: serverScheduledTime.toISOString(), timezone: validTimezone, timeValidation }, timestamp: new Date() }); res.json({ success: true, paymentId: scheduledPayment.id, scheduledTime: serverScheduledTime.toISOString(), businessTime: timeWindowValidation.businessTime, timezone: validTimezone, processingWindow: { earliest: serverScheduledTime.toISOString(), latest: serverScheduledTime.clone().add(1, 'hour').toISOString() } }); } catch (error) { console.error('Payment scheduling error:', { error: error.message, stack: error.stack, userId: req.user?.id, requestData: req.body, timestamp: new Date() }); res.status(500).json({ error: 'Payment scheduling failed', timestamp: new Date().toISOString() }); } } );

💡 Why This Fix Works

The secure implementation establishes server-side time authority that validates all timestamps, implements comprehensive timezone validation with DST handling, uses atomic scheduling operations with distributed locking, provides proper business hours validation with configurable rules, includes idempotency protection for duplicate requests, and maintains detailed audit trails for all time-based operations. The system ensures that time-based business logic cannot be manipulated by client-side timestamp tampering.

Why it happens

Applications that accept and trust client-provided timestamps for business logic decisions allow attackers to manipulate time values to bypass restrictions, access features outside permitted time windows, or exploit time-sensitive functionality.

Root causes

Client-Side Timestamp Manipulation and Trust Issues

Applications that accept and trust client-provided timestamps for business logic decisions allow attackers to manipulate time values to bypass restrictions, access features outside permitted time windows, or exploit time-sensitive functionality.

Preview example – JAVASCRIPT
// VULNERABLE: Client-side timestamp manipulation vulnerabilities
const express = require('express');
const app = express();

// PROBLEM: Trusting client-provided timestamps for business logic
app.post('/api/schedule-payment', async (req, res) => {
    const {
        amount,
        recipientId,
        scheduledTime,  // DANGEROUS: Client-provided timestamp
        timezone        // DANGEROUS: Client-provided timezone
    } = req.body;
    
    try {
        // PROBLEM 1: Using client timestamp without validation
        const scheduledDate = new Date(scheduledTime);
        
        // VULNERABLE: Basic validation allows past dates
        if (scheduledDate < new Date()) {
            return res.status(400).json({ error: 'Cannot schedule payment in the past' });
        }
        
        // PROBLEM 2: Not validating reasonable future limits
        const payment = await ScheduledPayment.create({
            userId: req.user.id,
            amount,
            recipientId,
            scheduledTime: scheduledDate,  // Using client time
            timezone,                      // Using client timezone
            status: 'scheduled',
            createdAt: new Date()
        });
        
        res.json({
            success: true,
            paymentId: payment.id,
            scheduledFor: scheduledDate
        });
        
    } catch (error) {
        res.status(500).json({ error: 'Payment scheduling failed' });
    }
});

// VULNERABLE: Promotional access based on client time
app.post('/api/apply-promotion', async (req, res) => {
    const {
        promoCode,
        currentTime,     // DANGEROUS: Client-provided current time
        userTimezone     // DANGEROUS: Client-provided timezone
    } = req.body;
    
    try {
        const promotion = await Promotion.findOne({ code: promoCode });
        
        if (!promotion) {
            return res.status(404).json({ error: 'Promotion not found' });
        }
        
        // PROBLEM: Using client-provided time for validation
        const clientCurrentTime = new Date(currentTime);
        
        // VULNERABLE: Time window validation using client time
        if (clientCurrentTime < promotion.startTime || 
            clientCurrentTime > promotion.endTime) {
            return res.status(400).json({ error: 'Promotion not currently active' });
        }
        
        // PROBLEM: Timezone manipulation opportunities
        const userLocalTime = this.convertToTimezone(clientCurrentTime, userTimezone);
        
        // Apply promotion without server-side time verification
        const result = await applyPromotionToUser(req.user.id, promotion.id);
        
        res.json({
            success: true,
            promotion: promotion.name,
            appliedAt: clientCurrentTime
        });
        
    } catch (error) {
        res.status(500).json({ error: 'Promotion application failed' });
    }
});

// PROBLEM 3: Time-based feature access with client control
app.get('/api/daily-bonus', async (req, res) => {
    const { requestTime, timezone } = req.query;
    
    try {
        const user = await User.findById(req.user.id);
        
        // VULNERABLE: Using client-provided request time
        const clientRequestTime = new Date(requestTime || Date.now());
        
        // Get last bonus claim time
        const lastBonusTime = user.lastBonusClaimedAt;
        
        if (lastBonusTime) {
            // PROBLEM: Time difference calculation using client time
            const timeDiff = clientRequestTime - lastBonusTime;
            const hoursSinceLastBonus = timeDiff / (1000 * 60 * 60);
            
            // VULNERABLE: 24-hour cooldown based on client time
            if (hoursSinceLastBonus < 24) {
                return res.status(429).json({
                    error: 'Daily bonus already claimed',
                    nextAvailableIn: (24 - hoursSinceLastBonus) * 60 * 60 * 1000
                });
            }
        }
        
        // Grant daily bonus
        user.dailyBonusPoints += 100;
        user.lastBonusClaimedAt = clientRequestTime;  // DANGEROUS: Using client time
        await user.save();
        
        res.json({
            success: true,
            bonusPoints: 100,
            claimedAt: clientRequestTime
        });
        
    } catch (error) {
        res.status(500).json({ error: 'Bonus claim failed' });
    }
});

// VULNERABLE: Event scheduling with time manipulation
app.post('/api/events/:eventId/register', async (req, res) => {
    const { eventId } = req.params;
    const { registrationTime } = req.body;
    
    try {
        const event = await Event.findById(eventId);
        
        if (!event) {
            return res.status(404).json({ error: 'Event not found' });
        }
        
        // PROBLEM: Using client-provided registration time
        const regTime = new Date(registrationTime || Date.now());
        
        // VULNERABLE: Early bird pricing based on client time
        const isEarlyBird = regTime < event.earlyBirdDeadline;
        const price = isEarlyBird ? event.earlyBirdPrice : event.regularPrice;
        
        // PROBLEM: Registration deadline check using client time
        if (regTime > event.registrationDeadline) {
            return res.status(400).json({ error: 'Registration deadline has passed' });
        }
        
        const registration = await EventRegistration.create({
            userId: req.user.id,
            eventId,
            price,
            isEarlyBird,
            registeredAt: regTime  // DANGEROUS: Client-controlled timestamp
        });
        
        res.json({
            success: true,
            registrationId: registration.id,
            price,
            isEarlyBird
        });
        
    } catch (error) {
        res.status(500).json({ error: 'Event registration failed' });
    }
});

// Attack scenarios:
// 1. Set scheduledTime far in future to bypass payment limits
// 2. Manipulate currentTime to access expired promotions
// 3. Set requestTime in past to bypass daily bonus cooldowns
// 4. Use registrationTime before early bird deadline
// 5. Timezone manipulation to extend access windows

Timezone Confusion and Locale Manipulation Attacks

Applications that improperly handle timezone conversions, daylight saving time transitions, or locale-specific time formatting can be exploited to access restricted functionality, bypass time-based limitations, or cause temporal inconsistencies in business logic.

Preview example – JAVASCRIPT
// VULNERABLE: Timezone confusion and locale manipulation vulnerabilities
const moment = require('moment-timezone');
const express = require('express');
const app = express();

// PROBLEM: Inconsistent timezone handling across application
class TimeZoneManager {
    constructor() {
        this.defaultTimezone = 'UTC';
    }
    
    // VULNERABLE: Accepting any timezone without validation
    convertToUserTimezone(utcTime, userTimezone) {
        try {
            // PROBLEM: No validation of timezone input
            return moment(utcTime).tz(userTimezone).format();
        } catch (error) {
            // PROBLEM: Fallback without proper error handling
            return moment(utcTime).format();
        }
    }
    
    // PROBLEM: Mixing timezone-aware and timezone-naive operations
    getUserBusinessHours(userId, userTimezone) {
        // VULNERABLE: Business hours defined in server timezone
        const businessHours = {
            start: 9,  // 9 AM server time
            end: 17    // 5 PM server time
        };
        
        // PROBLEM: Converting business hours using user timezone
        const now = moment().tz(userTimezone);
        const currentHour = now.hour();
        
        // VULNERABLE: Logic assumes same-day comparison
        return {
            isBusinessHours: currentHour >= businessHours.start && 
                           currentHour < businessHours.end,
            userLocalTime: now.format(),
            businessHours
        };
    }
}

const timezoneManager = new TimeZoneManager();

// VULNERABLE: Trading window validation with timezone issues
app.post('/api/trading/execute', async (req, res) => {
    const {
        symbol,
        quantity,
        userTimezone,
        marketTimezone    // DANGEROUS: Client-provided market timezone
    } = req.body;
    
    try {
        // PROBLEM: Using client-provided market timezone
        const marketTime = moment().tz(marketTimezone);
        const marketHour = marketTime.hour();
        const marketDay = marketTime.day();
        
        // VULNERABLE: Market hours check with client-controlled timezone
        const isMarketOpen = marketDay >= 1 && marketDay <= 5 && // Monday-Friday
                           marketHour >= 9 && marketHour < 16;   // 9 AM - 4 PM
        
        if (!isMarketOpen) {
            return res.status(400).json({
                error: 'Market is currently closed',
                marketTime: marketTime.format(),
                nextOpenTime: this.calculateNextMarketOpen(marketTime)
            });
        }
        
        // PROBLEM: Different timezone for trade recording
        const trade = await Trade.create({
            userId: req.user.id,
            symbol,
            quantity,
            executedAt: new Date(), // Server time (UTC)
            marketTime: marketTime.toDate(), // Client-provided market time
            userTimezone
        });
        
        res.json({
            success: true,
            tradeId: trade.id,
            executedAt: trade.executedAt,
            marketTime: marketTime.format()
        });
        
    } catch (error) {
        res.status(500).json({ error: 'Trade execution failed' });
    }
});

// VULNERABLE: Subscription billing with timezone manipulation
app.post('/api/subscription/renew', async (req, res) => {
    const { userTimezone, billingCycle } = req.body;
    
    try {
        const user = await User.findById(req.user.id);
        const subscription = await Subscription.findOne({ userId: req.user.id });
        
        if (!subscription) {
            return res.status(404).json({ error: 'No subscription found' });
        }
        
        // PROBLEM: Renewal date calculation using user timezone
        const userLocalTime = moment().tz(userTimezone);
        const currentPeriodEnd = moment(subscription.currentPeriodEnd).tz(userTimezone);
        
        // VULNERABLE: Grace period calculation affected by timezone
        const gracePeriodHours = 24;
        const gracePeriodEnd = currentPeriodEnd.clone().add(gracePeriodHours, 'hours');
        
        // PROBLEM: Different timezone for billing vs grace period
        if (userLocalTime.isAfter(gracePeriodEnd)) {
            return res.status(400).json({
                error: 'Subscription renewal period has expired',
                expiredAt: gracePeriodEnd.format(),
                currentTime: userLocalTime.format()
            });
        }
        
        // Calculate next billing date
        let nextBillingDate;
        switch (billingCycle) {
            case 'monthly':
                nextBillingDate = userLocalTime.clone().add(1, 'month');
                break;
            case 'yearly':
                nextBillingDate = userLocalTime.clone().add(1, 'year');
                break;
        }
        
        // PROBLEM: Storing dates in different timezones
        subscription.currentPeriodEnd = nextBillingDate.utc().toDate();
        subscription.lastRenewalTimezone = userTimezone;
        await subscription.save();
        
        res.json({
            success: true,
            nextBillingDate: nextBillingDate.format(),
            timezone: userTimezone
        });
        
    } catch (error) {
        res.status(500).json({ error: 'Subscription renewal failed' });
    }
});

// VULNERABLE: Time-sensitive discount application
app.post('/api/discounts/flash-sale', async (req, res) => {
    const { productId, userTimezone } = req.body;
    
    try {
        // PROBLEM: Flash sale timing based on user timezone
        const userTime = moment().tz(userTimezone);
        const saleHour = userTime.hour();
        
        // VULNERABLE: Flash sale hours vary by user timezone
        const isFlashSaleActive = (saleHour >= 12 && saleHour < 14); // 12-2 PM user time
        
        if (!isFlashSaleActive) {
            return res.status(400).json({
                error: 'Flash sale is not currently active',
                currentTime: userTime.format(),
                nextSaleTime: userTime.clone().add(1, 'day').hour(12).minute(0).second(0).format()
            });
        }
        
        const product = await Product.findById(productId);
        
        // PROBLEM: Discount percentage varies by timezone
        const discountPercentage = this.calculateTimezoneBasedDiscount(userTimezone);
        
        const discountedPrice = product.price * (1 - discountPercentage / 100);
        
        // Apply flash sale discount
        const flashSale = await FlashSaleDiscount.create({
            userId: req.user.id,
            productId,
            originalPrice: product.price,
            discountedPrice,
            discountPercentage,
            appliedAt: userTime.toDate(),  // User timezone
            userTimezone,
            expiresAt: userTime.clone().add(2, 'hours').toDate()
        });
        
        res.json({
            success: true,
            discountId: flashSale.id,
            originalPrice: product.price,
            discountedPrice,
            discountPercentage,
            expiresAt: flashSale.expiresAt
        });
        
    } catch (error) {
        res.status(500).json({ error: 'Flash sale application failed' });
    }
});

// PROBLEM: Daylight saving time transition handling
app.get('/api/schedule/availability', async (req, res) => {
    const { date, timezone } = req.query;
    
    try {
        // VULNERABLE: Not handling DST transitions
        const requestedDate = moment.tz(date, timezone);
        
        // PROBLEM: Assuming fixed hour differences
        const businessStart = requestedDate.clone().hour(9).minute(0);
        const businessEnd = requestedDate.clone().hour(17).minute(0);
        
        // VULNERABLE: DST transition can cause booking conflicts
        const existingBookings = await Booking.find({
            date: {
                $gte: businessStart.toDate(),
                $lt: businessEnd.toDate()
            }
        });
        
        // Generate available slots without DST consideration
        const availableSlots = [];
        let current = businessStart.clone();
        
        while (current.isBefore(businessEnd)) {
            const isBooked = existingBookings.some(booking => 
                moment(booking.startTime).isSame(current)
            );
            
            if (!isBooked) {
                availableSlots.push({
                    startTime: current.format(),
                    endTime: current.clone().add(1, 'hour').format(),
                    timezone
                });
            }
            
            current.add(1, 'hour');
        }
        
        res.json({
            date: requestedDate.format('YYYY-MM-DD'),
            timezone,
            availableSlots,
            businessHours: {
                start: businessStart.format(),
                end: businessEnd.format()
            }
        });
        
    } catch (error) {
        res.status(500).json({ error: 'Availability check failed' });
    }
});

// Attack scenarios:
// 1. Use different timezones to access markets outside hours
// 2. Manipulate timezone to extend subscription grace periods
// 3. Exploit DST transitions for double bookings
// 4. Use timezone offsets to access flash sales multiple times
// 5. Billing timezone manipulation to delay payments

Scheduling System Race Conditions and Temporal Conflicts

Scheduling and reservation systems that don't properly handle concurrent booking attempts, time slot conflicts, or temporal race conditions can be exploited to create double bookings, bypass capacity limits, or manipulate scheduling algorithms.

Preview example – JAVASCRIPT
// VULNERABLE: Scheduling system with race conditions and temporal conflicts
const express = require('express');
const app = express();

// PROBLEM: Non-atomic scheduling operations
class SchedulingManager {
    constructor() {
        this.pendingBookings = new Map(); // In-memory state is problematic
    }
    
    // VULNERABLE: Booking availability check with race conditions
    async checkAvailability(resourceId, startTime, endTime) {
        try {
            const startDate = new Date(startTime);
            const endDate = new Date(endTime);
            
            // PROBLEM 1: Non-atomic availability check
            const existingBookings = await Booking.find({
                resourceId,
                status: { $in: ['confirmed', 'pending'] },
                $or: [
                    // Overlapping bookings check
                    {
                        startTime: { $lt: endDate },
                        endTime: { $gt: startDate }
                    }
                ]
            });
            
            // PROBLEM 2: Capacity check without considering pending operations
            const resource = await Resource.findById(resourceId);
            const bookedCapacity = existingBookings.reduce((sum, booking) => 
                sum + booking.capacity, 0
            );
            
            const availableCapacity = resource.maxCapacity - bookedCapacity;
            
            return {
                isAvailable: availableCapacity > 0,
                availableCapacity,
                existingBookings: existingBookings.length
            };
            
        } catch (error) {
            throw error;
        }
    }
    
    // VULNERABLE: Booking creation with race condition
    async createBooking(bookingData) {
        const {
            resourceId,
            userId,
            startTime,
            endTime,
            capacity
        } = bookingData;
        
        try {
            // PROBLEM: Check-then-act race condition
            const availability = await this.checkAvailability(resourceId, startTime, endTime);
            
            if (!availability.isAvailable || availability.availableCapacity < capacity) {
                throw new Error('Insufficient capacity available');
            }
            
            // RACE CONDITION: Multiple requests can pass availability check
            const booking = await Booking.create({
                resourceId,
                userId,
                startTime: new Date(startTime),
                endTime: new Date(endTime),
                capacity,
                status: 'pending',
                createdAt: new Date()
            });
            
            // PROBLEM: Status update separate from creation
            setTimeout(async () => {
                try {
                    booking.status = 'confirmed';
                    await booking.save();
                } catch (error) {
                    console.error('Booking confirmation failed:', error);
                }
            }, 5000); // 5 second delay
            
            return booking;
            
        } catch (error) {
            throw error;
        }
    }
    
    // VULNERABLE: Bulk booking with inconsistent validation
    async createBulkBookings(bookingsData) {
        const results = [];
        
        // PROBLEM: Sequential processing allows race conditions
        for (const bookingData of bookingsData) {
            try {
                const booking = await this.createBooking(bookingData);
                results.push({ success: true, booking });
            } catch (error) {
                results.push({ success: false, error: error.message });
            }
        }
        
        return results;
    }
}

const schedulingManager = new SchedulingManager();

// VULNERABLE: Meeting room booking endpoint
app.post('/api/bookings/meeting-room', async (req, res) => {
    const {
        roomId,
        startTime,
        endTime,
        attendees,
        recurring
    } = req.body;
    
    try {
        // PROBLEM: No request deduplication
        const bookingData = {
            resourceId: roomId,
            userId: req.user.id,
            startTime,
            endTime,
            capacity: attendees.length
        };
        
        let bookings = [];
        
        if (recurring) {
            // VULNERABLE: Recurring bookings without proper validation
            const { frequency, count } = recurring;
            
            for (let i = 0; i < count; i++) {
                const startDate = new Date(startTime);
                startDate.setDate(startDate.getDate() + (i * frequency));
                
                const endDate = new Date(endTime);
                endDate.setDate(endDate.getDate() + (i * frequency));
                
                // PROBLEM: Each recurring booking processed separately
                const booking = await schedulingManager.createBooking({
                    ...bookingData,
                    startTime: startDate,
                    endTime: endDate
                });
                
                bookings.push(booking);
            }
        } else {
            const booking = await schedulingManager.createBooking(bookingData);
            bookings.push(booking);
        }
        
        res.json({
            success: true,
            bookings: bookings.map(b => ({
                id: b.id,
                startTime: b.startTime,
                endTime: b.endTime,
                status: b.status
            }))
        });
        
    } catch (error) {
        res.status(400).json({ error: error.message });
    }
});

// VULNERABLE: Event ticket booking with overbooking issues
app.post('/api/events/:eventId/book-tickets', async (req, res) => {
    const { eventId } = req.params;
    const { quantity, ticketType } = req.body;
    
    try {
        const event = await Event.findById(eventId);
        
        if (!event) {
            return res.status(404).json({ error: 'Event not found' });
        }
        
        // PROBLEM: Non-atomic ticket availability check
        const bookedTickets = await Ticket.countDocuments({
            eventId,
            status: { $in: ['confirmed', 'pending'] }
        });
        
        const availableTickets = event.maxTickets - bookedTickets;
        
        // RACE CONDITION: Multiple users can book last tickets
        if (availableTickets < quantity) {
            return res.status(400).json({
                error: 'Not enough tickets available',
                available: availableTickets,
                requested: quantity
            });
        }
        
        // PROBLEM: Ticket creation without atomicity
        const tickets = [];
        for (let i = 0; i < quantity; i++) {
            const ticket = await Ticket.create({
                eventId,
                userId: req.user.id,
                ticketType,
                price: event.ticketPrices[ticketType],
                status: 'pending',
                bookedAt: new Date()
            });
            
            tickets.push(ticket);
        }
        
        // PROBLEM: Payment processing separate from booking
        const totalAmount = tickets.reduce((sum, ticket) => sum + ticket.price, 0);
        
        // Simulate payment processing delay
        setTimeout(async () => {
            try {
                await Ticket.updateMany(
                    { _id: { $in: tickets.map(t => t.id) } },
                    { status: 'confirmed' }
                );
            } catch (error) {
                console.error('Ticket confirmation failed:', error);
            }
        }, 10000); // 10 second delay
        
        res.json({
            success: true,
            tickets: tickets.map(t => ({
                id: t.id,
                ticketType: t.ticketType,
                price: t.price
            })),
            totalAmount
        });
        
    } catch (error) {
        res.status(500).json({ error: 'Ticket booking failed' });
    }
});

// VULNERABLE: Appointment scheduling with time conflicts
app.post('/api/appointments/schedule', async (req, res) => {
    const {
        providerId,
        serviceId,
        preferredTime,
        duration,
        clientTimezone
    } = req.body;
    
    try {
        // PROBLEM: Time conversion without proper validation
        const appointmentTime = new Date(preferredTime);
        const endTime = new Date(appointmentTime.getTime() + (duration * 60 * 1000));
        
        // VULNERABLE: Provider availability check
        const provider = await Provider.findById(providerId);
        const conflictingAppointments = await Appointment.find({
            providerId,
            status: { $in: ['confirmed', 'pending'] },
            startTime: { $lt: endTime },
            endTime: { $gt: appointmentTime }
        });
        
        // PROBLEM: Simple conflict check without buffer time
        if (conflictingAppointments.length > 0) {
            return res.status(409).json({
                error: 'Time slot not available',
                conflicts: conflictingAppointments.length
            });
        }
        
        // RACE CONDITION: Multiple clients can book same slot
        const appointment = await Appointment.create({
            providerId,
            clientId: req.user.id,
            serviceId,
            startTime: appointmentTime,
            endTime,
            duration,
            clientTimezone,
            status: 'pending',
            scheduledAt: new Date()
        });
        
        // PROBLEM: Confirmation email sent before final validation
        await sendAppointmentConfirmation(req.user.email, appointment);
        
        res.json({
            success: true,
            appointmentId: appointment.id,
            startTime: appointment.startTime,
            endTime: appointment.endTime
        });
        
    } catch (error) {
        res.status(500).json({ error: 'Appointment scheduling failed' });
    }
});

// Attack scenarios:
// 1. Concurrent booking requests for same time slot
// 2. Rapid-fire ticket purchases to exceed capacity
// 3. Recurring booking spam to block resources
// 4. Race conditions during payment processing delays
// 5. Timezone manipulation to create conflicting bookings

Time-Based Access Control and Expiration Vulnerabilities

Access control systems that rely on time-based expiration, session timeouts, or temporal permissions can be exploited through clock manipulation, session extension attacks, or bypassing time-based restrictions to maintain unauthorized access.

Preview example – JAVASCRIPT
// VULNERABLE: Time-based access control with manipulation vulnerabilities
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

// PROBLEM: Session management with time manipulation vulnerabilities
class SessionManager {
    constructor() {
        this.activeSessions = new Map();
        this.sessionTimeout = 30 * 60 * 1000; // 30 minutes
    }
    
    // VULNERABLE: Session creation with client-influenced expiration
    createSession(userId, clientInfo) {
        const sessionId = this.generateSessionId();
        const now = Date.now();
        
        // PROBLEM: Using client-provided timezone for expiration calculation
        const clientTimezone = clientInfo.timezone;
        const timezoneOffset = this.getTimezoneOffset(clientTimezone);
        
        const session = {
            sessionId,
            userId,
            createdAt: now,
            lastActivity: now,
            // VULNERABLE: Expiration affected by timezone offset
            expiresAt: now + this.sessionTimeout + timezoneOffset,
            clientInfo,
            isExtended: false
        };
        
        this.activeSessions.set(sessionId, session);
        return session;
    }
    
    // PROBLEM: Session validation trusting client timestamps
    validateSession(sessionId, clientTimestamp) {
        const session = this.activeSessions.get(sessionId);
        
        if (!session) {
            return { valid: false, reason: 'session_not_found' };
        }
        
        // VULNERABLE: Using client-provided timestamp for validation
        const clientTime = new Date(clientTimestamp).getTime();
        
        // PROBLEM: Session expiration check using client time
        if (clientTime > session.expiresAt) {
            this.activeSessions.delete(sessionId);
            return { valid: false, reason: 'session_expired' };
        }
        
        // VULNERABLE: Last activity update with client time
        session.lastActivity = clientTime;
        
        return { valid: true, session };
    }
    
    // PROBLEM: Session extension with inadequate controls
    extendSession(sessionId, extensionHours, adminOverride) {
        const session = this.activeSessions.get(sessionId);
        
        if (!session) {
            throw new Error('Session not found');
        }
        
        // VULNERABLE: Admin override without proper validation
        if (adminOverride === 'true') {
            session.expiresAt = Date.now() + (extensionHours * 60 * 60 * 1000);
            session.isExtended = true;
            return session;
        }
        
        // PROBLEM: Extension limits not properly enforced
        const maxExtension = 24 * 60 * 60 * 1000; // 24 hours
        const requestedExtension = extensionHours * 60 * 60 * 1000;
        
        if (requestedExtension > maxExtension) {
            throw new Error('Extension period too long');
        }
        
        session.expiresAt += requestedExtension;
        return session;
    }
}

const sessionManager = new SessionManager();

// VULNERABLE: JWT-based authentication with time manipulation
app.post('/api/auth/login', async (req, res) => {
    const {
        email,
        password,
        requestTime,     // DANGEROUS: Client-provided request time
        timezone,        // DANGEROUS: Client-provided timezone
        extendedSession  // DANGEROUS: Client-controlled session extension
    } = req.body;
    
    try {
        const user = await User.findOne({ email });
        
        if (!user || !await bcrypt.compare(password, user.hashedPassword)) {
            return res.status(401).json({ error: 'Invalid credentials' });
        }
        
        // PROBLEM: JWT expiration based on client-provided time
        const clientRequestTime = new Date(requestTime || Date.now());
        let tokenExpiration = '1h'; // Default 1 hour
        
        // VULNERABLE: Extended session based on client request
        if (extendedSession === 'true') {
            tokenExpiration = '24h'; // 24 hours for extended sessions
        }
        
        // PROBLEM: JWT issued with client-influenced timestamp
        const token = jwt.sign(
            {
                userId: user.id,
                email: user.email,
                issuedAt: clientRequestTime.toISOString(),
                timezone: timezone
            },
            process.env.JWT_SECRET,
            {
                expiresIn: tokenExpiration,
                issuer: 'auth-service'
            }
        );
        
        // Create session with client timezone influence
        const session = sessionManager.createSession(user.id, {
            ip: req.ip,
            userAgent: req.get('User-Agent'),
            timezone: timezone
        });
        
        res.json({
            success: true,
            token,
            sessionId: session.sessionId,
            expiresAt: session.expiresAt,
            timezone: timezone
        });
        
    } catch (error) {
        res.status(500).json({ error: 'Authentication failed' });
    }
});

// VULNERABLE: Premium feature access with time-based restrictions
app.get('/api/premium-features/:feature', async (req, res) => {
    const { feature } = req.params;
    const { accessTime, userTimezone } = req.query;
    
    try {
        const user = await User.findById(req.user.id).populate('subscription');
        
        if (!user.subscription) {
            return res.status(403).json({ error: 'Premium subscription required' });
        }
        
        // PROBLEM: Using client-provided access time
        const clientAccessTime = new Date(accessTime || Date.now());
        
        // VULNERABLE: Subscription expiration check with client time
        if (clientAccessTime > user.subscription.expiresAt) {
            return res.status(403).json({
                error: 'Subscription has expired',
                expiredAt: user.subscription.expiresAt,
                currentTime: clientAccessTime
            });
        }
        
        // PROBLEM: Feature access window based on user timezone
        const userLocalTime = moment(clientAccessTime).tz(userTimezone);
        const accessHour = userLocalTime.hour();
        
        // VULNERABLE: Time-based feature restrictions using client timezone
        const premiumFeatureHours = {
            'advanced-analytics': { start: 9, end: 17 }, // 9 AM - 5 PM
            'priority-support': { start: 8, end: 20 },   // 8 AM - 8 PM
            'bulk-export': { start: 22, end: 6 }        // 10 PM - 6 AM (off-peak)
        };
        
        const featureWindow = premiumFeatureHours[feature];
        if (featureWindow) {
            let isWithinWindow;
            
            if (featureWindow.start > featureWindow.end) {
                // Overnight window (like bulk-export)
                isWithinWindow = accessHour >= featureWindow.start || accessHour < featureWindow.end;
            } else {
                isWithinWindow = accessHour >= featureWindow.start && accessHour < featureWindow.end;
            }
            
            if (!isWithinWindow) {
                return res.status(403).json({
                    error: 'Feature not available during current hours',
                    availableWindow: featureWindow,
                    currentHour: accessHour,
                    userTimezone
                });
            }
        }
        
        // Grant access to premium feature
        const featureData = await getPremiumFeatureData(feature, user.id);
        
        res.json({
            success: true,
            feature,
            data: featureData,
            accessedAt: clientAccessTime,
            userTimezone
        });
        
    } catch (error) {
        res.status(500).json({ error: 'Feature access failed' });
    }
});

// VULNERABLE: Temporary access token generation
app.post('/api/temp-access/generate', async (req, res) => {
    const {
        resourceId,
        requestedDuration,   // DANGEROUS: Client-controlled duration
        validFrom,          // DANGEROUS: Client-provided start time
        timezone            // DANGEROUS: Client-provided timezone
    } = req.body;
    
    try {
        // PROBLEM: Trusting client-provided validity period
        const startTime = new Date(validFrom || Date.now());
        const durationMs = parseInt(requestedDuration) * 60 * 1000; // Duration in minutes
        
        // VULNERABLE: No maximum duration limit
        const endTime = new Date(startTime.getTime() + durationMs);
        
        // PROBLEM: Timezone affects token validity calculation
        const timezoneOffset = this.getTimezoneOffsetMs(timezone);
        const adjustedEndTime = new Date(endTime.getTime() + timezoneOffset);
        
        const tempToken = {
            tokenId: crypto.randomUUID(),
            userId: req.user.id,
            resourceId,
            validFrom: startTime,
            validUntil: adjustedEndTime,
            timezone,
            createdAt: new Date()
        };
        
        // Store temporary token
        await TempAccessToken.create(tempToken);
        
        res.json({
            success: true,
            token: tempToken.tokenId,
            validFrom: tempToken.validFrom,
            validUntil: tempToken.validUntil,
            duration: Math.round(durationMs / 60000) + ' minutes'
        });
        
    } catch (error) {
        res.status(500).json({ error: 'Token generation failed' });
    }
});

// VULNERABLE: Session extension endpoint
app.post('/api/session/extend', async (req, res) => {
    const {
        sessionId,
        extensionHours,
        adminKey           // DANGEROUS: Simple admin override
    } = req.body;
    
    try {
        // PROBLEM: Weak admin validation
        const adminOverride = adminKey === process.env.ADMIN_EXTENSION_KEY;
        
        const session = sessionManager.extendSession(
            sessionId,
            parseInt(extensionHours),
            adminOverride
        );
        
        res.json({
            success: true,
            sessionId: session.sessionId,
            newExpiresAt: session.expiresAt,
            isExtended: session.isExtended
        });
        
    } catch (error) {
        res.status(400).json({ error: error.message });
    }
});

// Attack scenarios:
// 1. Manipulate requestTime to extend JWT validity
// 2. Use timezone offsets to bypass time-based restrictions
// 3. Extend sessions indefinitely with admin override
// 4. Access premium features outside allowed hours
// 5. Create temporary tokens with excessive duration

Fixes

1

Implement Server-Side Time Authority and Validation

Establish a centralized server-side time authority that controls all time-based business logic, validates client timestamps against reasonable bounds, and maintains temporal consistency across the application.

View implementation – JAVASCRIPT
// SECURE: Server-side time authority implementation
const moment = require('moment-timezone');
const redis = require('redis');
const crypto = require('crypto');

const redisClient = redis.createClient(process.env.REDIS_URL);

class SecureTimeAuthority {
    constructor() {
        this.serverTimezone = 'UTC';
        this.maxClockSkew = 5 * 60 * 1000; // 5 minutes
        this.supportedTimezones = moment.tz.names();
        this.timeValidationCache = new Map();
    }
    
    // Get authoritative server time
    getServerTime() {
        return {
            timestamp: Date.now(),
            iso: new Date().toISOString(),
            timezone: this.serverTimezone
        };
    }
    
    // Validate client-provided timestamp against server time
    validateClientTimestamp(clientTimestamp, allowedSkew = this.maxClockSkew) {
        const serverTime = Date.now();
        const clientTime = new Date(clientTimestamp).getTime();
        
        if (isNaN(clientTime)) {
            throw new Error('Invalid timestamp format');
        }
        
        const timeDifference = Math.abs(serverTime - clientTime);
        
        if (timeDifference > allowedSkew) {
            throw new Error(`Clock skew too large: ${Math.round(timeDifference / 1000)}s (max: ${Math.round(allowedSkew / 1000)}s)`);
        }
        
        return {
            isValid: true,
            serverTime,
            clientTime,
            skew: clientTime - serverTime
        };
    }
    
    // Validate timezone and normalize to supported format
    validateTimezone(timezone) {
        if (!timezone) {
            return this.serverTimezone;
        }
        
        // Check if timezone is supported
        if (!this.supportedTimezones.includes(timezone)) {
            throw new Error(`Unsupported timezone: ${timezone}`);
        }
        
        // Validate timezone is currently valid (not deprecated)
        try {
            moment.tz.zone(timezone);
            return timezone;
        } catch (error) {
            throw new Error(`Invalid timezone: ${timezone}`);
        }
    }
    
    // Convert time to specific timezone with validation
    convertToTimezone(utcTimestamp, targetTimezone) {
        const validTimezone = this.validateTimezone(targetTimezone);
        
        try {
            return moment.utc(utcTimestamp).tz(validTimezone);
        } catch (error) {
            throw new Error(`Timezone conversion failed: ${error.message}`);
        }
    }
    
    // Validate time window for business operations
    validateTimeWindow(operation, userTimezone = null) {
        const serverTime = moment.utc();
        const operationRules = this.getOperationTimeRules(operation);
        
        if (!operationRules) {
            return { allowed: true, reason: 'no_time_restrictions' };
        }
        
        // Use server timezone for business rules unless specifically configured
        const businessTimezone = operationRules.timezone || this.serverTimezone;
        const businessTime = serverTime.clone().tz(businessTimezone);
        
        // Check day of week restrictions
        if (operationRules.allowedDays) {
            const currentDay = businessTime.day();
            if (!operationRules.allowedDays.includes(currentDay)) {
                return {
                    allowed: false,
                    reason: 'outside_allowed_days',
                    currentDay,
                    allowedDays: operationRules.allowedDays
                };
            }
        }
        
        // Check hour restrictions
        if (operationRules.allowedHours) {
            const currentHour = businessTime.hour();
            const { start, end } = operationRules.allowedHours;
            
            let isWithinHours;
            if (start > end) {
                // Overnight hours (e.g., 22:00 to 06:00)
                isWithinHours = currentHour >= start || currentHour < end;
            } else {
                isWithinHours = currentHour >= start && currentHour < end;
            }
            
            if (!isWithinHours) {
                return {
                    allowed: false,
                    reason: 'outside_business_hours',
                    currentHour,
                    allowedHours: operationRules.allowedHours,
                    businessTimezone
                };
            }
        }
        
        // Check for maintenance windows
        const maintenanceWindow = await this.checkMaintenanceWindow(operation);
        if (maintenanceWindow.inMaintenance) {
            return {
                allowed: false,
                reason: 'maintenance_window',
                maintenanceEnd: maintenanceWindow.endTime
            };
        }
        
        return {
            allowed: true,
            businessTime: businessTime.toISOString(),
            businessTimezone
        };
    }
    
    // Get operation-specific time rules
    getOperationTimeRules(operation) {
        const timeRules = {
            'payment_processing': {
                timezone: 'America/New_York',
                allowedDays: [1, 2, 3, 4, 5], // Monday-Friday
                allowedHours: { start: 6, end: 22 } // 6 AM - 10 PM
            },
            'trading_operations': {
                timezone: 'America/New_York',
                allowedDays: [1, 2, 3, 4, 5],
                allowedHours: { start: 9, end: 16 } // 9 AM - 4 PM (market hours)
            },
            'bulk_operations': {
                timezone: 'UTC',
                allowedHours: { start: 22, end: 6 } // Off-peak hours
            },
            'subscription_billing': {
                timezone: 'UTC',
                allowedDays: [1, 2, 3, 4, 5, 6, 0], // All days
                allowedHours: { start: 0, end: 24 } // All hours
            }
        };
        
        return timeRules[operation];
    }
    
    // Check for system maintenance windows
    async checkMaintenanceWindow(operation) {
        const maintenanceKey = `maintenance:${operation}`;
        const maintenanceData = await redisClient.get(maintenanceKey);
        
        if (!maintenanceData) {
            return { inMaintenance: false };
        }
        
        const maintenance = JSON.parse(maintenanceData);
        const now = Date.now();
        
        if (now >= maintenance.startTime && now <= maintenance.endTime) {
            return {
                inMaintenance: true,
                startTime: maintenance.startTime,
                endTime: maintenance.endTime,
                reason: maintenance.reason
            };
        }
        
        // Clean up expired maintenance windows
        if (now > maintenance.endTime) {
            await redisClient.del(maintenanceKey);
        }
        
        return { inMaintenance: false };
    }
    
    // Generate cryptographically secure timestamps
    generateSecureTimestamp(additionalEntropy = '') {
        const timestamp = Date.now();
        const nonce = crypto.randomBytes(16).toString('hex');
        const entropy = additionalEntropy || crypto.randomBytes(8).toString('hex');
        
        const combinedData = `${timestamp}:${nonce}:${entropy}`;
        const hash = crypto.createHash('sha256').update(combinedData).digest('hex');
        
        return {
            timestamp,
            nonce,
            hash,
            iso: new Date(timestamp).toISOString()
        };
    }
    
    // Validate time-based expiration with server authority
    validateExpiration(expirationTime, gracePeroidMs = 0) {
        const serverTime = Date.now();
        const expiration = new Date(expirationTime).getTime();
        
        if (isNaN(expiration)) {
            throw new Error('Invalid expiration time format');
        }
        
        const isExpired = serverTime > (expiration + gracePeroidMs);
        
        return {
            isExpired,
            serverTime,
            expirationTime: expiration,
            timeRemaining: Math.max(0, expiration + gracePeroidMs - serverTime)
        };
    }
}

// Secure scheduling system with proper time validation
class SecureSchedulingSystem {
    constructor() {
        this.timeAuthority = new SecureTimeAuthority();
        this.lockTimeout = 30000; // 30 seconds
    }
    
    // Schedule operation with comprehensive time validation
    async scheduleOperation(operationData, userId) {
        const {
            operationType,
            scheduledTime,
            timezone,
            duration,
            parameters
        } = operationData;
        
        try {
            // Validate operation type
            const allowedOperations = ['payment', 'backup', 'maintenance', 'notification'];
            if (!allowedOperations.includes(operationType)) {
                throw new Error(`Unsupported operation type: ${operationType}`);
            }
            
            // Validate timezone
            const validTimezone = this.timeAuthority.validateTimezone(timezone);
            
            // Convert scheduled time to server timezone
            const serverScheduledTime = moment.tz(scheduledTime, validTimezone).utc();
            
            // Validate scheduling window
            const serverTime = moment.utc();
            const minScheduleAdvance = moment.duration(5, 'minutes');
            const maxScheduleAdvance = moment.duration(365, 'days');
            
            if (serverScheduledTime.isBefore(serverTime.add(minScheduleAdvance))) {
                throw new Error('Operation must be scheduled at least 5 minutes in advance');
            }
            
            if (serverScheduledTime.isAfter(serverTime.add(maxScheduleAdvance))) {
                throw new Error('Operation cannot be scheduled more than 1 year in advance');
            }
            
            // Validate operation time window
            const timeWindowValidation = await this.timeAuthority.validateTimeWindow(
                operationType,
                validTimezone
            );
            
            // Check if scheduled time falls within allowed window
            const scheduledTimeInBusinessTZ = serverScheduledTime.clone().tz(
                timeWindowValidation.businessTimezone || 'UTC'
            );
            
            const operationRules = this.timeAuthority.getOperationTimeRules(operationType);
            if (operationRules) {
                // Validate day of week
                if (operationRules.allowedDays) {
                    const scheduledDay = scheduledTimeInBusinessTZ.day();
                    if (!operationRules.allowedDays.includes(scheduledDay)) {
                        throw new Error(`Operation not allowed on ${scheduledTimeInBusinessTZ.format('dddd')}`);
                    }
                }
                
                // Validate hour
                if (operationRules.allowedHours) {
                    const scheduledHour = scheduledTimeInBusinessTZ.hour();
                    const { start, end } = operationRules.allowedHours;
                    
                    let isValidHour;
                    if (start > end) {
                        isValidHour = scheduledHour >= start || scheduledHour < end;
                    } else {
                        isValidHour = scheduledHour >= start && scheduledHour < end;
                    }
                    
                    if (!isValidHour) {
                        throw new Error(`Operation not allowed at ${scheduledHour}:00 (allowed: ${start}:00-${end}:00)`);
                    }
                }
            }
            
            // Generate secure operation ID
            const secureTimestamp = this.timeAuthority.generateSecureTimestamp(
                `${operationType}:${userId}`
            );
            
            // Create scheduled operation
            const scheduledOperation = await ScheduledOperation.create({
                operationId: secureTimestamp.hash,
                operationType,
                userId,
                scheduledTime: serverScheduledTime.toDate(),
                originalTimezone: validTimezone,
                duration: duration || 0,
                parameters,
                status: 'scheduled',
                createdAt: new Date(),
                securityHash: secureTimestamp.hash
            });
            
            return {
                success: true,
                operationId: scheduledOperation.operationId,
                scheduledTime: serverScheduledTime.toISOString(),
                businessTime: scheduledTimeInBusinessTZ.format(),
                businessTimezone: timeWindowValidation.businessTimezone
            };
            
        } catch (error) {
            throw new Error(`Operation scheduling failed: ${error.message}`);
        }
    }
}
2

Implement Timezone-Safe Business Logic with DST Handling

Create a robust timezone handling system that properly manages daylight saving time transitions, validates timezone data, and ensures consistent business logic across different geographical regions.

View implementation – JAVASCRIPT
// SECURE: Timezone-safe business logic with DST handling
const moment = require('moment-timezone');
const { promisify } = require('util');
const redis = require('redis');

const redisClient = redis.createClient(process.env.REDIS_URL);

class SecureTimezoneManager {
    constructor() {
        this.supportedTimezones = new Set(moment.tz.names());
        this.timezoneValidationCache = new Map();
        this.dstTransitionCache = new Map();
    }
    
    // Validate and normalize timezone input
    async validateTimezone(timezone, userLocation = null) {
        if (!timezone) {
            return await this.inferTimezoneFromLocation(userLocation) || 'UTC';
        }
        
        // Check cache first
        const cacheKey = `tz_validation:${timezone}`;
        const cached = this.timezoneValidationCache.get(cacheKey);
        if (cached && (Date.now() - cached.timestamp) < 3600000) { // 1 hour cache
            return cached.result;
        }
        
        // Validate timezone exists
        if (!this.supportedTimezones.has(timezone)) {
            throw new Error(`Unsupported timezone: ${timezone}`);
        }
        
        // Check if timezone is currently valid (not deprecated)
        try {
            const zone = moment.tz.zone(timezone);
            if (!zone) {
                throw new Error(`Invalid timezone: ${timezone}`);
            }
            
            // Cache validation result
            this.timezoneValidationCache.set(cacheKey, {
                result: timezone,
                timestamp: Date.now()
            });
            
            return timezone;
            
        } catch (error) {
            throw new Error(`Timezone validation failed: ${error.message}`);
        }
    }
    
    // Convert UTC time to user timezone with DST awareness
    convertToUserTimezone(utcTime, userTimezone) {
        const validTimezone = await this.validateTimezone(userTimezone);
        
        try {
            const moment_utc = moment.utc(utcTime);
            const converted = moment_utc.tz(validTimezone);
            
            return {
                localTime: converted.format(),
                timezone: validTimezone,
                offset: converted.format('Z'),
                isDST: converted.isDST(),
                timestamp: converted.valueOf()
            };
            
        } catch (error) {
            throw new Error(`Timezone conversion failed: ${error.message}`);
        }
    }
    
    // Handle DST transitions safely
    async handleDSTTransition(dateTime, timezone, operation = 'forward') {
        const validTimezone = await this.validateTimezone(timezone);
        
        try {
            const moment_dt = moment.tz(dateTime, validTimezone);
            
            // Check if the time falls during a DST transition
            const dstTransition = this.checkDSTTransition(moment_dt, validTimezone);
            
            if (dstTransition.isTransition) {
                return this.resolveDSTAmbiguity(moment_dt, dstTransition, operation);
            }
            
            return {
                resolvedTime: moment_dt.format(),
                timezone: validTimezone,
                isDST: moment_dt.isDST(),
                transitionInfo: null
            };
            
        } catch (error) {
            throw new Error(`DST transition handling failed: ${error.message}`);
        }
    }
    
    // Check for DST transition periods
    checkDSTTransition(momentObj, timezone) {
        const date = momentObj.format('YYYY-MM-DD');
        const year = momentObj.year();
        
        // Get DST transition dates for the year
        const transitions = this.getDSTTransitions(year, timezone);
        
        for (const transition of transitions) {
            // Check if date falls on transition day
            if (momentObj.format('YYYY-MM-DD') === transition.date) {
                const hour = momentObj.hour();
                
                if (transition.type === 'spring_forward') {
                    // Spring forward: 2:00 AM becomes 3:00 AM
                    if (hour >= 2 && hour < 3) {
                        return {
                            isTransition: true,
                            type: 'spring_forward',
                            skippedHour: hour,
                            transition
                        };
                    }
                } else if (transition.type === 'fall_back') {
                    // Fall back: 2:00 AM occurs twice
                    if (hour >= 1 && hour < 3) {
                        return {
                            isTransition: true,
                            type: 'fall_back',
                            ambiguousHour: hour,
                            transition
                        };
                    }
                }
            }
        }
        
        return { isTransition: false };
    }
    
    // Resolve DST ambiguity
    resolveDSTAmbiguity(momentObj, transitionInfo, operation) {
        if (transitionInfo.type === 'spring_forward') {
            // For skipped hours, move forward to the next valid time
            const resolved = momentObj.clone().add(1, 'hour');
            
            return {
                resolvedTime: resolved.format(),
                timezone: momentObj.tz(),
                isDST: resolved.isDST(),
                transitionInfo: {
                    type: 'spring_forward',
                    originalTime: momentObj.format(),
                    adjustedBy: '1 hour forward',
                    reason: 'Skipped hour during DST transition'
                }
            };
            
        } else if (transitionInfo.type === 'fall_back') {
            // For ambiguous hours, use operation preference
            let resolved;
            
            if (operation === 'first_occurrence') {
                resolved = momentObj.clone().dst(true); // First occurrence (DST)
            } else {
                resolved = momentObj.clone().dst(false); // Second occurrence (Standard)
            }
            
            return {
                resolvedTime: resolved.format(),
                timezone: momentObj.tz(),
                isDST: resolved.isDST(),
                transitionInfo: {
                    type: 'fall_back',
                    ambiguousTime: momentObj.format(),
                    selectedOccurrence: operation,
                    reason: 'Ambiguous hour during DST transition'
                }
            };
        }
    }
    
    // Get DST transition dates for a given year
    getDSTTransitions(year, timezone) {
        const cacheKey = `dst_transitions:${year}:${timezone}`;
        const cached = this.dstTransitionCache.get(cacheKey);
        
        if (cached) {
            return cached;
        }
        
        const transitions = [];
        
        // Check each month for DST transitions
        for (let month = 0; month < 12; month++) {
            const startOfMonth = moment.tz([year, month], timezone);
            const endOfMonth = startOfMonth.clone().endOf('month');
            
            let current = startOfMonth.clone();
            let previousDST = current.isDST();
            
            while (current.isSameOrBefore(endOfMonth)) {
                const currentDST = current.isDST();
                
                if (currentDST !== previousDST) {
                    transitions.push({
                        date: current.format('YYYY-MM-DD'),
                        type: currentDST ? 'spring_forward' : 'fall_back',
                        timestamp: current.valueOf()
                    });
                }
                
                previousDST = currentDST;
                current.add(1, 'day');
            }
        }
        
        // Cache transitions for 1 year
        this.dstTransitionCache.set(cacheKey, transitions);
        setTimeout(() => {
            this.dstTransitionCache.delete(cacheKey);
        }, 365 * 24 * 60 * 60 * 1000);
        
        return transitions;
    }
}

// Secure business hours validation with timezone handling
class SecureBusinessHoursManager {
    constructor() {
        this.timezoneManager = new SecureTimezoneManager();
        this.businessRules = new Map();
    }
    
    // Define business hours for different operations and regions
    setBusinessRules(operationType, rules) {
        this.businessRules.set(operationType, {
            ...rules,
            timezone: rules.timezone || 'UTC',
            createdAt: Date.now()
        });
    }
    
    // Validate if operation is allowed during current business hours
    async validateBusinessHours(operationType, userTimezone = 'UTC') {
        const rules = this.businessRules.get(operationType);
        
        if (!rules) {
            return {
                allowed: true,
                reason: 'no_business_hour_restrictions'
            };
        }
        
        try {
            // Get current time in business timezone
            const businessTZ = await this.timezoneManager.validateTimezone(rules.timezone);
            const businessTime = moment.tz(businessTZ);
            
            // Handle DST transitions
            const dstHandled = await this.timezoneManager.handleDSTTransition(
                businessTime.format(),
                businessTZ,
                'forward'
            );
            
            const currentBusinessTime = moment(dstHandled.resolvedTime);
            
            // Check day of week
            if (rules.allowedDays) {
                const currentDay = currentBusinessTime.day();
                if (!rules.allowedDays.includes(currentDay)) {
                    return {
                        allowed: false,
                        reason: 'outside_business_days',
                        currentDay: currentBusinessTime.format('dddd'),
                        allowedDays: rules.allowedDays.map(d => 
                            moment().day(d).format('dddd')
                        ),
                        businessTimezone: businessTZ
                    };
                }
            }
            
            // Check business hours
            if (rules.hours) {
                const currentHour = currentBusinessTime.hour();
                const currentMinute = currentBusinessTime.minute();
                const currentTimeMinutes = currentHour * 60 + currentMinute;
                
                const { start, end } = rules.hours;
                const startMinutes = this.parseTimeToMinutes(start);
                const endMinutes = this.parseTimeToMinutes(end);
                
                let isWithinHours;
                
                if (startMinutes > endMinutes) {
                    // Overnight hours (e.g., 22:00 to 06:00)
                    isWithinHours = currentTimeMinutes >= startMinutes || 
                                  currentTimeMinutes < endMinutes;
                } else {
                    isWithinHours = currentTimeMinutes >= startMinutes && 
                                  currentTimeMinutes < endMinutes;
                }
                
                if (!isWithinHours) {
                    const nextBusinessTime = this.calculateNextBusinessTime(
                        currentBusinessTime,
                        rules
                    );
                    
                    return {
                        allowed: false,
                        reason: 'outside_business_hours',
                        currentTime: currentBusinessTime.format('HH:mm'),
                        businessHours: `${start} - ${end}`,
                        businessTimezone: businessTZ,
                        nextBusinessTime: nextBusinessTime.format(),
                        dstInfo: dstHandled.transitionInfo
                    };
                }
            }
            
            // Check for holidays
            if (rules.holidays) {
                const currentDate = currentBusinessTime.format('YYYY-MM-DD');
                if (rules.holidays.includes(currentDate)) {
                    return {
                        allowed: false,
                        reason: 'holiday',
                        currentDate,
                        businessTimezone: businessTZ
                    };
                }
            }
            
            return {
                allowed: true,
                businessTime: currentBusinessTime.format(),
                businessTimezone: businessTZ,
                dstInfo: dstHandled.transitionInfo
            };
            
        } catch (error) {
            throw new Error(`Business hours validation failed: ${error.message}`);
        }
    }
    
    // Calculate next available business time
    calculateNextBusinessTime(currentTime, rules) {
        let nextTime = currentTime.clone();
        
        // If current day is not a business day, find next business day
        if (rules.allowedDays) {
            while (!rules.allowedDays.includes(nextTime.day())) {
                nextTime.add(1, 'day').startOf('day');
            }
        }
        
        // Set to business hours start time
        if (rules.hours) {
            const startTime = this.parseTimeToMinutes(rules.hours.start);
            const startHour = Math.floor(startTime / 60);
            const startMinute = startTime % 60;
            
            nextTime.hour(startHour).minute(startMinute).second(0);
            
            // If we're past business hours today, move to next business day
            if (nextTime.isSameOrBefore(currentTime)) {
                nextTime.add(1, 'day');
                
                // Find next business day
                if (rules.allowedDays) {
                    while (!rules.allowedDays.includes(nextTime.day())) {
                        nextTime.add(1, 'day');
                    }
                }
            }
        }
        
        return nextTime;
    }
    
    // Parse time string to minutes since midnight
    parseTimeToMinutes(timeString) {
        const [hours, minutes] = timeString.split(':').map(Number);
        return hours * 60 + (minutes || 0);
    }
}
3

Implement Atomic Scheduling with Distributed Locking

Create a secure scheduling system that uses distributed locking, atomic operations, and comprehensive conflict detection to prevent race conditions and ensure scheduling integrity.

View implementation – JAVASCRIPT
// SECURE: Atomic scheduling system with distributed locking
const redis = require('redis');
const mongoose = require('mongoose');
const { v4: uuidv4 } = require('uuid');
const crypto = require('crypto');

const redisClient = redis.createClient(process.env.REDIS_URL);

class SecureAtomicScheduler {
    constructor() {
        this.lockTimeout = 30000; // 30 seconds
        this.lockPrefix = 'scheduler_lock:';
        this.timeAuthority = new SecureTimeAuthority();
    }
    
    // Create booking with atomic operations and conflict detection
    async createSecureBooking(bookingData, idempotencyKey) {
        const {
            resourceId,
            userId,
            startTime,
            endTime,
            capacity,
            bookingType
        } = bookingData;
        
        // Validate input data
        const validation = await this.validateBookingData(bookingData);
        if (!validation.isValid) {
            throw new Error(`Invalid booking data: ${validation.errors.join(', ')}`);
        }
        
        // Check for duplicate booking using idempotency key
        if (idempotencyKey) {
            const existingBooking = await Booking.findOne({
                idempotencyKey,
                status: { $in: ['confirmed', 'pending'] }
            });
            
            if (existingBooking) {
                return {
                    success: true,
                    booking: existingBooking,
                    isIdempotent: true
                };
            }
        }
        
        // Create lock keys for atomic operations
        const lockKeys = this.generateLockKeys(resourceId, startTime, endTime);
        const lockValues = lockKeys.map(() => uuidv4());
        
        try {
            // Acquire distributed locks
            const locksAcquired = await this.acquireMultipleLocks(lockKeys, lockValues);
            if (!locksAcquired) {
                throw new Error('Unable to acquire booking locks, please try again');
            }
            
            // Start database transaction
            const session = await mongoose.startSession();
            const result = await session.withTransaction(async () => {
                // Validate resource availability atomically
                const availabilityCheck = await this.checkAtomicAvailability(
                    resourceId,
                    startTime,
                    endTime,
                    capacity,
                    session
                );
                
                if (!availabilityCheck.isAvailable) {
                    throw new Error(`Resource not available: ${availabilityCheck.reason}`);
                }
                
                // Validate business rules
                const businessValidation = await this.validateBusinessRules(
                    userId,
                    resourceId,
                    startTime,
                    endTime,
                    bookingType,
                    session
                );
                
                if (!businessValidation.isValid) {
                    throw new Error(`Business rule violation: ${businessValidation.reason}`);
                }
                
                // Create booking with atomic capacity reservation
                const booking = await this.createAtomicBooking({
                    resourceId,
                    userId,
                    startTime: new Date(startTime),
                    endTime: new Date(endTime),
                    capacity,
                    bookingType,
                    idempotencyKey,
                    status: 'pending',
                    reservationHash: this.generateReservationHash(bookingData),
                    createdAt: new Date()
                }, session);
                
                // Update resource capacity atomically
                await this.updateResourceCapacity(
                    resourceId,
                    startTime,
                    endTime,
                    capacity,
                    'reserve',
                    session
                );
                
                // Create audit trail
                await this.createBookingAuditLog({
                    bookingId: booking.id,
                    action: 'created',
                    userId,
                    resourceId,
                    details: {
                        startTime,
                        endTime,
                        capacity,
                        availabilityCheck,
                        businessValidation
                    },
                    timestamp: new Date()
                }, session);
                
                return booking;
                
            }, {
                readConcern: { level: 'snapshot' },
                writeConcern: { w: 'majority', j: true },
                readPreference: 'primary'
            });
            
            // Schedule automatic confirmation/cancellation
            await this.scheduleBookingTimeout(result.id);
            
            return {
                success: true,
                booking: result,
                isIdempotent: false
            };
            
        } finally {
            // Always release locks
            await this.releaseMultipleLocks(lockKeys, lockValues);
        }
    }
    
    // Validate booking data comprehensively
    async validateBookingData(bookingData) {
        const errors = [];
        const {
            resourceId,
            userId,
            startTime,
            endTime,
            capacity
        } = bookingData;
        
        // Validate resource exists
        const resource = await Resource.findById(resourceId);
        if (!resource) {
            errors.push('Resource not found');
        } else if (resource.status !== 'active') {
            errors.push('Resource is not active');
        }
        
        // Validate user exists and is active
        const user = await User.findById(userId);
        if (!user) {
            errors.push('User not found');
        } else if (user.status !== 'active') {
            errors.push('User account is not active');
        }
        
        // Validate time format and logic
        const start = new Date(startTime);
        const end = new Date(endTime);
        
        if (isNaN(start.getTime()) || isNaN(end.getTime())) {
            errors.push('Invalid date format');
        } else {
            if (start >= end) {
                errors.push('Start time must be before end time');
            }
            
            // Validate against server time
            const timeValidation = this.timeAuthority.validateClientTimestamp(startTime);
            if (!timeValidation.isValid) {
                errors.push('Start time has excessive clock skew');
            }
            
            // Validate minimum advance booking time
            const minAdvanceMs = 5 * 60 * 1000; // 5 minutes
            if (start.getTime() < Date.now() + minAdvanceMs) {
                errors.push('Booking must be made at least 5 minutes in advance');
            }
            
            // Validate maximum advance booking time
            const maxAdvanceMs = 365 * 24 * 60 * 60 * 1000; // 1 year
            if (start.getTime() > Date.now() + maxAdvanceMs) {
                errors.push('Booking cannot be made more than 1 year in advance');
            }
        }
        
        // Validate capacity
        if (capacity <= 0) {
            errors.push('Capacity must be positive');
        } else if (resource && capacity > resource.maxCapacity) {
            errors.push(`Capacity exceeds resource maximum (${resource.maxCapacity})`);
        }
        
        return {
            isValid: errors.length === 0,
            errors
        };
    }
    
    // Check resource availability atomically
    async checkAtomicAvailability(resourceId, startTime, endTime, requestedCapacity, session) {
        const start = new Date(startTime);
        const end = new Date(endTime);
        
        // Get resource with current capacity information
        const resource = await Resource.findById(resourceId).session(session);
        
        if (!resource) {
            return {
                isAvailable: false,
                reason: 'Resource not found'
            };
        }
        
        // Find overlapping bookings
        const overlappingBookings = await Booking.find({
            resourceId,
            status: { $in: ['confirmed', 'pending'] },
            $or: [
                {
                    startTime: { $lt: end },
                    endTime: { $gt: start }
                }
            ]
        }).session(session);
        
        // Calculate used capacity during the requested time period
        const usedCapacity = overlappingBookings.reduce((total, booking) => {
            return total + booking.capacity;
        }, 0);
        
        const availableCapacity = resource.maxCapacity - usedCapacity;
        
        if (availableCapacity < requestedCapacity) {
            return {
                isAvailable: false,
                reason: 'Insufficient capacity',
                availableCapacity,
                requestedCapacity,
                overlappingBookings: overlappingBookings.length
            };
        }
        
        // Check resource-specific constraints
        const constraintCheck = await this.checkResourceConstraints(
            resource,
            start,
            end,
            requestedCapacity
        );
        
        if (!constraintCheck.isValid) {
            return {
                isAvailable: false,
                reason: constraintCheck.reason
            };
        }
        
        return {
            isAvailable: true,
            availableCapacity,
            overlappingBookings: overlappingBookings.length
        };
    }
    
    // Validate business rules for booking
    async validateBusinessRules(userId, resourceId, startTime, endTime, bookingType, session) {
        const user = await User.findById(userId).session(session);
        const resource = await Resource.findById(resourceId).session(session);
        
        // Check user booking limits
        const userBookingLimits = await this.checkUserBookingLimits(
            userId,
            startTime,
            endTime,
            session
        );
        
        if (!userBookingLimits.isValid) {
            return {
                isValid: false,
                reason: userBookingLimits.reason
            };
        }
        
        // Check booking type restrictions
        if (resource.allowedBookingTypes && 
            !resource.allowedBookingTypes.includes(bookingType)) {
            return {
                isValid: false,
                reason: `Booking type '${bookingType}' not allowed for this resource`
            };
        }
        
        // Check time-based restrictions
        const timeRestrictions = await this.checkTimeRestrictions(
            resource,
            startTime,
            endTime
        );
        
        if (!timeRestrictions.isValid) {
            return {
                isValid: false,
                reason: timeRestrictions.reason
            };
        }
        
        return { isValid: true };
    }
    
    // Generate lock keys for distributed locking
    generateLockKeys(resourceId, startTime, endTime) {
        const start = new Date(startTime);
        const end = new Date(endTime);
        
        // Create lock keys for each hour in the booking period
        const lockKeys = [];
        const current = new Date(start);
        current.setMinutes(0, 0, 0); // Round down to hour
        
        while (current < end) {
            const lockKey = `${this.lockPrefix}${resourceId}:${current.toISOString()}`;
            lockKeys.push(lockKey);
            current.setHours(current.getHours() + 1);
        }
        
        // Add resource-level lock
        lockKeys.push(`${this.lockPrefix}resource:${resourceId}`);
        
        return lockKeys;
    }
    
    // Acquire multiple locks atomically
    async acquireMultipleLocks(lockKeys, lockValues) {
        const acquiredLocks = [];
        
        try {
            // Sort lock keys to prevent deadlocks
            const sortedPairs = lockKeys.map((key, index) => ({ key, value: lockValues[index] }))
                                      .sort((a, b) => a.key.localeCompare(b.key));
            
            for (const { key, value } of sortedPairs) {
                const acquired = await this.acquireSingleLock(key, value);
                if (!acquired) {
                    // Release any locks we've already acquired
                    for (const lock of acquiredLocks) {
                        await this.releaseSingleLock(lock.key, lock.value);
                    }
                    return false;
                }
                acquiredLocks.push({ key, value });
            }
            
            return true;
            
        } catch (error) {
            // Release any acquired locks on error
            for (const lock of acquiredLocks) {
                await this.releaseSingleLock(lock.key, lock.value);
            }
            throw error;
        }
    }
    
    // Generate reservation hash for integrity verification
    generateReservationHash(bookingData) {
        const hashData = {
            resourceId: bookingData.resourceId,
            userId: bookingData.userId,
            startTime: bookingData.startTime,
            endTime: bookingData.endTime,
            capacity: bookingData.capacity,
            timestamp: Date.now()
        };
        
        const dataString = JSON.stringify(hashData, Object.keys(hashData).sort());
        return crypto.createHash('sha256').update(dataString).digest('hex');
    }
}

Detect This Vulnerability in Your Code

Sourcery automatically identifies time-based business logic vulnerabilities and temporal manipulation attacks and many other security issues in your codebase.