Improper Restriction of Power Consumption

Description

Improper Restriction of Power Consumption occurs when software operates in environments where power is a limited resource that cannot be automatically replenished (such as battery-powered devices), but fails to properly restrict the amount of power that its operation consumes. This vulnerability is particularly relevant for mobile devices, embedded systems, IoT devices, and any battery-powered equipment. Attackers can exploit this weakness by triggering operations that cause excessive power drain through components like CPU-intensive calculations, display brightness, GPS receivers, wireless radios, disk I/O, sound systems, cameras, or USB interfaces.

Risk

Exploitation of this vulnerability can lead to complete denial of service by draining the device's battery. For mobile devices, this can render phones unusable during critical situations. In IoT and embedded systems, power exhaustion can disable security systems, medical devices, or industrial controls. Continuous power drain attacks can reduce battery lifespan through excessive charge cycles. In safety-critical systems, unexpected power loss can have severe consequences. The attack can be persistent and difficult to detect, as power consumption may appear related to normal operations rather than malicious activity.

Solution

Implement power consumption budgets and monitoring for all operations. Limit the frequency of power-intensive operations. Use power-efficient algorithms and hardware features like sleep modes. Implement rate limiting for operations that trigger high power consumption. Monitor and alert on abnormal power usage patterns. Design applications to gracefully handle low-power conditions. Validate inputs that control power-consuming operations to prevent abuse. Consider implementing power usage caps per time period. Use hardware power management features effectively. For mobile apps, follow platform guidelines for background processing and wake locks.

Common Consequences

ImpactDetails
AvailabilityScope: Availability

DoS: Resource Consumption - Excessive power drain depletes batteries, causing devices to shut down and become unavailable.
AvailabilityScope: Availability

DoS: Crash/Exit/Restart - Power exhaustion can cause applications and entire devices to cease functioning.

Example Code

Vulnerable Code

// Vulnerable: Android app with unrestricted GPS usage
public class VulnerableLocationService extends Service {

    private LocationManager locationManager;

    @Override
    public void onCreate() {
        locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
    }

    public void startTracking(int intervalMs) {
        // Vulnerable: No validation of interval, GPS always on
        locationManager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER,
            intervalMs,  // Attacker can set to 0 for constant updates
            0,
            locationListener
        );

        // Vulnerable: No power consideration, GPS drains battery fast
    }
}

// Attack: Start tracking with intervalMs=0 to drain battery quickly
// Vulnerable: Unrestricted wake lock usage
public class VulnerableBackgroundTask {

    private PowerManager.WakeLock wakeLock;

    public void startTask(Context context) {
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);

        // Vulnerable: Acquiring wake lock without timeout
        wakeLock = pm.newWakeLock(
            PowerManager.PARTIAL_WAKE_LOCK,
            "MyApp::BackgroundTask"
        );
        wakeLock.acquire();  // No timeout - keeps CPU running indefinitely

        // If task never completes or crashes, battery drains
    }

    // Vulnerable: May never be called if task fails
    public void stopTask() {
        if (wakeLock != null && wakeLock.isHeld()) {
            wakeLock.release();
        }
    }
}
// Vulnerable: iOS app with constant network polling
class VulnerableNetworkPoller {

    var timer: Timer?

    func startPolling(intervalSeconds: Double) {
        // Vulnerable: No minimum interval, no power state check
        timer = Timer.scheduledTimer(
            withTimeInterval: intervalSeconds,  // Could be 0.001
            repeats: true
        ) { _ in
            self.fetchData()
        }
    }

    func fetchData() {
        // Each network request prevents sleep and uses radio
        URLSession.shared.dataTask(with: url) { data, response, error in
            // Process data
        }.resume()
    }
}

// Attack: Set interval to 0.001 for 1000 requests/second
// Vulnerable: Embedded system without power management
void vulnerable_sensor_read(void) {
    // Vulnerable: Sensor always on, no sleep modes
    while (1) {
        // Constant sensor reading without delay
        int value = read_sensor();
        process_data(value);

        // No sleep, no power management
        // CPU and sensor always at full power
    }
}
# Vulnerable: IoT device with constant display
class VulnerableDisplay:

    def __init__(self):
        self.brightness = 100  # Maximum brightness

    def show_message(self, message):
        # Vulnerable: No timeout, display stays on forever
        set_display_brightness(self.brightness)
        display_text(message)

        # Display never turns off, draining power

Fixed Code

// Fixed: Android app with power-aware GPS usage
public class FixedLocationService extends Service {

    private LocationManager locationManager;
    private static final long MIN_UPDATE_INTERVAL_MS = 10000;  // 10 seconds minimum
    private static final long MAX_ACTIVE_TIME_MS = 300000;  // 5 minutes max
    private Handler timeoutHandler = new Handler(Looper.getMainLooper());

    @Override
    public void onCreate() {
        locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
    }

    public void startTracking(long requestedIntervalMs) {
        // Fixed: Enforce minimum interval
        long interval = Math.max(requestedIntervalMs, MIN_UPDATE_INTERVAL_MS);

        // Fixed: Check battery level before starting
        if (getBatteryLevel() < 20) {
            Log.w(TAG, "Battery too low for GPS tracking");
            return;
        }

        locationManager.requestLocationUpdates(
            LocationManager.GPS_PROVIDER,
            interval,
            10,  // 10 meter minimum distance
            locationListener
        );

        // Fixed: Automatic timeout to prevent indefinite GPS usage
        timeoutHandler.postDelayed(this::stopTracking, MAX_ACTIVE_TIME_MS);
    }

    public void stopTracking() {
        locationManager.removeUpdates(locationListener);
        timeoutHandler.removeCallbacksAndMessages(null);
    }

    private int getBatteryLevel() {
        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        Intent batteryStatus = registerReceiver(null, filter);
        int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
        int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
        return (int) (level * 100 / (float) scale);
    }
}
// Fixed: Safe wake lock usage with timeout
public class FixedBackgroundTask {

    private static final long MAX_WAKE_LOCK_MS = 60000;  // 1 minute max

    public void startTask(Context context) {
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);

        PowerManager.WakeLock wakeLock = pm.newWakeLock(
            PowerManager.PARTIAL_WAKE_LOCK,
            "MyApp::BackgroundTask"
        );

        // Fixed: Acquire with timeout - auto-releases after timeout
        wakeLock.acquire(MAX_WAKE_LOCK_MS);

        try {
            performTask();
        } finally {
            // Fixed: Always release in finally block
            if (wakeLock.isHeld()) {
                wakeLock.release();
            }
        }
    }
}

// Better: Use WorkManager for background tasks
public class FixedWorkManager {

    public void scheduleTask(Context context) {
        // WorkManager handles power management automatically
        Constraints constraints = new Constraints.Builder()
            .setRequiresBatteryNotLow(true)  // Only run when battery OK
            .build();

        OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(MyWorker.class)
            .setConstraints(constraints)
            .build();

        WorkManager.getInstance(context).enqueue(workRequest);
    }
}
// Fixed: iOS app with power-aware polling
class FixedNetworkPoller {

    var timer: Timer?
    private let minimumInterval: TimeInterval = 30  // 30 seconds minimum
    private let maxPollingDuration: TimeInterval = 300  // 5 minutes max
    private var startTime: Date?

    func startPolling(requestedInterval: TimeInterval) {
        // Fixed: Enforce minimum interval
        let interval = max(requestedInterval, minimumInterval)

        // Fixed: Check battery state
        UIDevice.current.isBatteryMonitoringEnabled = true
        if UIDevice.current.batteryLevel < 0.2 && UIDevice.current.batteryState != .charging {
            print("Battery too low for polling")
            return
        }

        startTime = Date()

        timer = Timer.scheduledTimer(
            withTimeInterval: interval,
            repeats: true
        ) { [weak self] timer in
            guard let self = self else {
                timer.invalidate()
                return
            }

            // Fixed: Check if max duration exceeded
            if let start = self.startTime,
               Date().timeIntervalSince(start) > self.maxPollingDuration {
                self.stopPolling()
                return
            }

            self.fetchData()
        }
    }

    func stopPolling() {
        timer?.invalidate()
        timer = nil
    }

    func fetchData() {
        let config = URLSessionConfiguration.default
        config.allowsCellularAccess = true
        config.isDiscretionary = true  // Let system optimize

        let session = URLSession(configuration: config)
        session.dataTask(with: url) { data, response, error in
            // Process data
        }.resume()
    }
}
// Fixed: Embedded system with power management
#include <power_management.h>

void fixed_sensor_read(void) {
    uint32_t last_read_time = 0;
    const uint32_t MIN_INTERVAL_MS = 1000;  // 1 second minimum

    while (1) {
        uint32_t current_time = get_system_time_ms();

        // Fixed: Rate limiting
        if (current_time - last_read_time < MIN_INTERVAL_MS) {
            // Enter low power mode while waiting
            enter_sleep_mode(MIN_INTERVAL_MS - (current_time - last_read_time));
            continue;
        }

        last_read_time = current_time;

        // Enable sensor only when needed
        sensor_power_on();
        int value = read_sensor();
        sensor_power_off();  // Disable sensor after reading

        process_data(value);

        // Enter low power mode between reads
        enter_sleep_mode(MIN_INTERVAL_MS);
    }
}

// Fixed: Power budget monitoring
typedef struct {
    uint32_t cpu_usage_budget;
    uint32_t sensor_usage_budget;
    uint32_t radio_usage_budget;
    uint32_t current_usage;
} PowerBudget;

bool can_perform_operation(PowerBudget *budget, uint32_t estimated_cost) {
    if (budget->current_usage + estimated_cost > budget->cpu_usage_budget) {
        return false;  // Would exceed power budget
    }
    return true;
}
# Fixed: IoT device with display timeout
import time
import threading

class FixedDisplay:

    def __init__(self):
        self.brightness = 50  # Default to 50% brightness
        self.timeout_seconds = 30  # Screen timeout
        self.timer = None

    def show_message(self, message, duration_seconds=None):
        # Use specified duration or default timeout
        timeout = duration_seconds or self.timeout_seconds

        # Fixed: Validate timeout
        timeout = min(timeout, 300)  # Max 5 minutes

        set_display_brightness(self.brightness)
        display_text(message)

        # Fixed: Auto-dim and turn off display
        self._schedule_timeout(timeout)

    def _schedule_timeout(self, timeout_seconds):
        # Cancel any existing timer
        if self.timer:
            self.timer.cancel()

        # Schedule display off
        self.timer = threading.Timer(
            timeout_seconds,
            self._turn_off_display
        )
        self.timer.start()

    def _turn_off_display(self):
        set_display_brightness(0)
        display_off()

    def set_power_mode(self, mode):
        if mode == 'low_power':
            self.brightness = 20
            self.timeout_seconds = 10
        elif mode == 'normal':
            self.brightness = 50
            self.timeout_seconds = 30

  • CWE-400: Uncontrolled Resource Consumption (parent)
  • CWE-770: Allocation of Resources Without Limits or Throttling (related)
  • CWE-399: Resource Management Errors (category)

References

  1. MITRE Corporation. "CWE-920: Improper Restriction of Power Consumption." https://cwe.mitre.org/data/definitions/920.html
  2. Android Developers. "Optimize for battery life." https://developer.android.com/training/monitoring-device-state/battery-monitoring
  3. Apple Developer Documentation. "Energy Efficiency Guide for iOS Apps."