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

ImpactDetails
ConfidentialityScope: Confidentiality

Known vulnerabilities expose confidential data indefinitely.
IntegrityScope: Integrity

Integrity compromises cannot be remediated through patching.
Access ControlScope: Access Control

Protection mechanism bypasses remain exploitable.
AvailabilityScope: 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.

  • 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

  1. MITRE Corporation. "CWE-1329: Reliance on Component That is Not Updateable." https://cwe.mitre.org/data/definitions/1329.html
  2. FDA. "Postmarket Management of Cybersecurity in Medical Devices"
  3. NIST. "Guidelines for IoT Device Security"