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
| Impact | Details |
|---|---|
| Availability | Scope: Availability DoS: Resource Consumption - Excessive power drain depletes batteries, causing devices to shut down and become unavailable. |
| Availability | Scope: 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
Related CWEs
- CWE-400: Uncontrolled Resource Consumption (parent)
- CWE-770: Allocation of Resources Without Limits or Throttling (related)
- CWE-399: Resource Management Errors (category)
References
- MITRE Corporation. "CWE-920: Improper Restriction of Power Consumption." https://cwe.mitre.org/data/definitions/920.html
- Android Developers. "Optimize for battery life." https://developer.android.com/training/monitoring-device-state/battery-monitoring
- Apple Developer Documentation. "Energy Efficiency Guide for iOS Apps."