Reliance on Component That is Not Updateable
Description
Reliance on Component That is Not Updateable occurs when a product contains a component that cannot be updated or patched to address vulnerabilities or critical bugs. When components lack updateability, organizations cannot remediate discovered security issues or defects, forcing operators to choose between accepting ongoing risk or undertaking costly replacement. The problem is particularly acute in industries like healthcare and industrial control where devices operate for decades. Both hardware (ROM, firmware) and software (unmaintained drivers/libraries) can exhibit this weakness.
Risk
Non-updateable components have severe implications. Known vulnerabilities remain exploitable indefinitely. Security patches cannot be applied. Regulatory compliance impossible. Costly device replacement required. Extended exposure windows. Supply chain risks. End-of-support scenarios. Permanent security gaps. Legacy system vulnerabilities. High impact in long-lifecycle industries (medical, industrial, automotive).
Solution
Mandate updateability for all components including ROM and firmware during requirements phase. Architect systems supporting component updates and necessary infrastructure during design phase. For hardware, implement in-field patchable mechanisms via hardware fuses (moderate effectiveness). Build necessary functionality enabling component updates during implementation phase. Plan for end-of-life and update mechanisms from the start.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Known vulnerabilities expose confidential data indefinitely. |
| Integrity | Scope: Integrity Integrity compromises cannot be remediated through patching. |
| Access Control | Scope: Access Control Protection mechanism bypasses remain exploitable. |
| Availability | Scope: Availability Denial of service vulnerabilities persist without patches. |
Example Code
Vulnerable Code
// Vulnerable: ROM-based boot code without patch capability
module vulnerable_boot_rom (
input wire clk,
input wire rst_n,
input wire [11:0] addr,
output reg [31:0] data
);
// VULNERABLE: Boot code in hardcoded ROM
// Cannot be updated if vulnerability is discovered
reg [31:0] rom [0:4095];
initial begin
// VULNERABLE: Boot code burned at manufacture
// If vulnerability found, entire device must be replaced
rom[0] = 32'h00000013; // NOP
rom[1] = 32'hFFF00097; // AUIPC
rom[2] = 32'h00808093; // ADDI
// ... thousands of instructions
// Including potentially vulnerable code
end
always @(posedge clk) begin
data <= rom[addr];
end
// No mechanism to update ROM contents
// Device is permanently vulnerable to any ROM bugs
endmodule
// Vulnerable: Cryptographic module with fixed algorithm
module vulnerable_crypto_fixed (
input wire clk,
input wire rst_n,
input wire [127:0] key,
input wire [127:0] plaintext,
input wire start,
output reg [127:0] ciphertext,
output reg done
);
// VULNERABLE: Hardcoded algorithm
// If cryptographic weakness found, cannot update
always @(posedge clk) begin
if (start) begin
// VULNERABLE: Fixed implementation
// Uses potentially weak algorithm forever
ciphertext <= aes_encrypt_fixed(plaintext, key);
done <= 1'b1;
end
end
// No ability to:
// - Update to stronger algorithm
// - Fix implementation bugs
// - Add countermeasures against new attacks
endmodule
// Vulnerable: Embedded system with non-updateable firmware
#include <stdint.h>
// VULNERABLE: Firmware in execute-in-place ROM
// Mapped directly to read-only memory region
const uint8_t __attribute__((section(".rom"))) firmware[] = {
// Entire firmware image
// Including any vulnerabilities
// Cannot be changed after manufacturing
};
// VULNERABLE: Hardcoded credentials
const char __attribute__((section(".rom"))) jtag_password[] = "factory_default";
// VULNERABLE: Fixed cryptographic keys
const uint8_t __attribute__((section(".rom"))) root_key[32] = {
0x01, 0x02, 0x03, /* ... */
};
// If any of these are compromised:
// - Cannot change password
// - Cannot revoke keys
// - Cannot patch vulnerabilities
// - Device must be physically replaced
// VULNERABLE: No update mechanism
void check_for_updates(void) {
// Not implemented - updates not possible
return;
}
# Vulnerable: IoT device with non-updateable components
# VULNERABLE: Hardcoded dependency without update path
FIXED_CRYPTO_VERSION = "openssl-1.0.1" # Known vulnerable version
# VULNERABLE: No firmware update capability
class VulnerableDevice:
def __init__(self):
self.firmware_version = "1.0.0" # Permanent
self.can_update = False
def check_update(self):
# VULNERABLE: Updates not supported
return None
def apply_update(self, update_package):
# VULNERABLE: No update mechanism
raise NotImplementedError("Device cannot be updated")
# Device ships with vulnerabilities that can never be fixed
Fixed Code
// Fixed: Boot system with ROM patching capability
module secure_patchable_boot (
input wire clk,
input wire rst_n,
input wire [11:0] addr,
output reg [31:0] data,
// Patch interface
input wire [11:0] patch_addr,
input wire [31:0] patch_data,
input wire patch_write,
input wire trusted_source,
// Patch enable fuses
input wire [15:0] patch_enable_fuses
);
// Original ROM (immutable)
reg [31:0] rom [0:4095];
// FIXED: Patch RAM overlay
reg [31:0] patch_ram [0:255]; // 256 patch slots
reg [11:0] patch_addresses [0:255]; // Addresses to patch
reg [255:0] patch_valid; // Which patches are active
initial begin
// Original boot code
rom[0] = 32'h00000013;
rom[1] = 32'hFFF00097;
// ...
end
// FIXED: Patch programming (from trusted source)
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
patch_valid <= 256'b0;
end else if (patch_write && trusted_source) begin
// FIXED: Allow patches from trusted firmware updates
patch_ram[patch_addr[7:0]] <= patch_data;
patch_addresses[patch_addr[7:0]] <= patch_addr;
patch_valid[patch_addr[7:0]] <= 1'b1;
end
end
// FIXED: Check patches before ROM read
reg patch_hit;
reg [7:0] patch_index;
always @(*) begin
patch_hit = 1'b0;
patch_index = 8'b0;
// Check if address matches any patch
for (integer i = 0; i < 256; i = i + 1) begin
if (patch_valid[i] && patch_addresses[i] == addr) begin
patch_hit = 1'b1;
patch_index = i;
end
end
end
// FIXED: Return patched or original data
always @(posedge clk) begin
if (patch_hit) begin
data <= patch_ram[patch_index]; // Patched value
end else begin
data <= rom[addr]; // Original ROM
end
end
endmodule
// Fixed: Updateable cryptographic module
module secure_updateable_crypto (
input wire clk,
input wire rst_n,
input wire [127:0] key,
input wire [127:0] plaintext,
input wire start,
input wire [2:0] algorithm_select, // FIXED: Selectable algorithm
output reg [127:0] ciphertext,
output reg done
);
// FIXED: Multiple algorithm implementations
wire [127:0] aes_result;
wire [127:0] chacha_result;
wire [127:0] future_result; // Reserved for updates
// FIXED: Algorithm selection allows updates
always @(posedge clk) begin
if (start) begin
case (algorithm_select)
3'b000: ciphertext <= aes_result;
3'b001: ciphertext <= chacha_result;
3'b010: ciphertext <= future_result;
default: ciphertext <= aes_result;
endcase
done <= 1'b1;
end
end
// FIXED: Can switch to new algorithm via configuration
// Can disable weak algorithms via fuses
endmodule
// Fixed: Embedded system with firmware update capability
#include <stdint.h>
#include <stdbool.h>
// FIXED: Firmware update support
typedef struct {
uint32_t version;
uint32_t size;
uint8_t signature[64];
uint8_t data[];
} firmware_update_t;
// FIXED: Updateable storage regions
#define FIRMWARE_REGION_A 0x10000000
#define FIRMWARE_REGION_B 0x10100000
#define ACTIVE_FIRMWARE_PTR 0x1FFF0000
// FIXED: Secure update mechanism
bool secure_apply_update(const firmware_update_t* update) {
// FIXED: Verify signature
if (!verify_firmware_signature(update)) {
return false;
}
// FIXED: Check version (anti-rollback)
uint32_t current_version = get_current_firmware_version();
if (update->version <= current_version) {
return false; // Prevent downgrade
}
// FIXED: Write to inactive region
uint32_t inactive_region = get_inactive_region();
if (!write_firmware(inactive_region, update->data, update->size)) {
return false;
}
// FIXED: Verify written data
if (!verify_firmware_integrity(inactive_region, update)) {
erase_region(inactive_region);
return false;
}
// FIXED: Switch active region
set_active_firmware(inactive_region);
// FIXED: Update version counter (anti-rollback)
increment_version_counter();
return true;
}
// FIXED: Credentials in updateable storage
bool update_credentials(const uint8_t* new_key, size_t key_len) {
// FIXED: Credentials can be updated securely
return secure_write_credential(new_key, key_len);
}
// FIXED: Key revocation support
bool revoke_key(uint32_t key_id) {
// FIXED: Can revoke compromised keys
return add_to_revocation_list(key_id);
}
# Fixed: IoT device with comprehensive update support
import hashlib
import json
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
class SecureUpdateableDevice:
def __init__(self):
self.firmware_version = "1.0.0"
self.update_public_key = load_update_key()
def check_update(self):
"""Check for available updates from secure server."""
# FIXED: Secure update check
response = secure_https_request(UPDATE_SERVER + "/check",
current_version=self.firmware_version)
if response.get('update_available'):
return response['update_info']
return None
def download_update(self, update_info):
"""Download update package securely."""
# FIXED: Secure download with integrity check
package = secure_https_request(update_info['url'])
expected_hash = update_info['sha256']
actual_hash = hashlib.sha256(package).hexdigest()
if actual_hash != expected_hash:
raise SecurityError("Update integrity check failed")
return package
def verify_update(self, package):
"""Verify update signature."""
# FIXED: Cryptographic signature verification
signature = package[:256]
firmware = package[256:]
try:
self.update_public_key.verify(
signature,
firmware,
padding.PKCS1v15(),
hashes.SHA256()
)
return True
except:
return False
def apply_update(self, package):
"""Apply verified update."""
if not self.verify_update(package):
raise SecurityError("Update signature invalid")
firmware = package[256:]
new_version = extract_version(firmware)
# FIXED: Anti-rollback check
if not is_newer_version(new_version, self.firmware_version):
raise SecurityError("Rollback attempt detected")
# FIXED: Apply update
write_to_inactive_partition(firmware)
verify_written_firmware()
switch_active_partition()
self.firmware_version = new_version
return True
def update_configuration(self, new_config):
"""Update device configuration securely."""
# FIXED: Configuration is updateable
if self.verify_config_signature(new_config):
self.apply_config(new_config)
CVE Examples
- CVE-2020-9054: Zyxel NAS devices with OS command injection vulnerabilities that are end-of-support and unpatched.
- CVE-2019-11477: Linux kernel TCP vulnerability affecting devices with non-updateable firmware.
Related CWEs
- CWE-664: Improper Control of a Resource Through its Lifetime (parent)
- CWE-1357: Reliance on Insufficiently Trustworthy Component (parent)
- CWE-1277: Firmware Not Updateable (child)
- CWE-1310: Missing Ability to Patch ROM Code (child)
References
- MITRE Corporation. "CWE-1329: Reliance on Component That is Not Updateable." https://cwe.mitre.org/data/definitions/1329.html
- FDA. "Postmarket Management of Cybersecurity in Medical Devices"
- NIST. "Guidelines for IoT Device Security"