Bare Metal Security: Implementing Secure Boot and Trusted Execution Environments (TEE)

Table of Contents

Ready to :innovate: together?

Bare Metal Security: Implementing Secure Boot and Trusted Execution Environments (TEE)

Security in bare-metal systems is not an added feature but a foundational property that must be designed in from the first instruction executed after reset. In environments without an operating system, common assumptions about isolation, privilege separation, and runtime protection no longer hold by default. Every line of initialization code, every memory mapping decision, and every hardware configuration step directly shapes the system’s attack surface. As a result, weaknesses introduced at boot time tend to be permanent, systemic, and difficult to mitigate later.

This article examines two core mechanisms used to establish trust in bare-metal systems: secure boot and Trusted Execution Environments (TEE). Rather than treating them as abstract security concepts, it focuses on their concrete implementation challenges. The goal is to move beyond checklist security. It is to develop an explicit understanding of what is actually protected, against which threat models, and at what cost in system complexity and flexibility.

Looking to Secure Your Bare Metal?
Our engineering team specialises in improving security for embedded and bare metal solutions. Boost efficiency, reduce downtime, and ensure long-term reliability with proven expertise.

Speak to an Expert →

Bare Metal Security: Why a simpler system can be harder to secure

Bare-metal systems are often assumed to be safer because they remove an operating system, background services, and large dependency trees. That inference is weak. In practice, bare metal collapses multiple trust boundaries into a single, privileged firmware image. As a result, a bug in early initialization or an unchecked memory write can immediately lead to full system compromise.

Saltzer and Schroeder’s classic security principle of least privilege reminds us that “Every program and every user of the system should operate using the least set of privileges necessary”. Bare-metal firmware typically violates this principle structurally: everything runs at maximum privilege.

With no process isolation, no virtual memory, and typically no mature runtime hardening, the “blast radius” of a defect is maximal by default.

Security also becomes tightly coupled to determinism. Interrupt handlers, DMA, and timing-critical code paths tend to bypass defensive checks to meet latency budgets, creating predictable shortcuts for an attacker. The boot path is a single point of failure. If the first-stage loader misconfigures clocks, memory regions, or exception vectors, later protections (Secure Boot, MPU policy, or even a TEE) may be logically present but practically unenforceable. This is where intrusion detection systems (IDS) could play a critical role in detecting unauthorized changes during this early stage. Google cloud services can assist with remote monitoring and early detection systems that integrate seamlessly with such environments.

Finally, bare-metal products live long. Cryptographic agility, key rotation, and safe firmware update become architectural requirements, not optional features, because field constraints often prevent replacing compromised devices at scale. Supporting this, a new paper published by Palo Alto Networks shows that nearly half (48.2%) of network connections from IoT and embedded devices originate from high-risk endpoints with unpatched or misconfigured components, which can enable lateral threat movement in enterprise networks.

Practical threat modeling in Bare Metal: Foundations for network security

A threat model for bare-metal systems should be an engineering tool. Its purpose is not to enumerate every conceivable risk, but to identify those that can be unambiguously tied to concrete code paths and hardware behavior. The first step is to identify trust boundaries. These include all components that execute privileged code or can influence its execution. Typical examples are the boot ROM, the first-stage bootloader, and the main firmware image. This group also includes debug interfaces (JTAG/SWD) and peripherals with direct memory access. Each trust boundary must have a clearly defined trust status and an explicit description of the impact of its compromise. In operational environments, the ability to reconstruct events from access logs related to debug sessions or firmware updates can significantly strengthen post-incident analysis.

The next step is to classify adversaries according to their actual capabilities. A remote adversary operates through network security measures or radio interfaces and is limited to the communication handling code. A local adversary has physical access to the device and can apply techniques such as fault injection or signal probing. Supply-chain threats refer to situations in which firmware, cryptographic keys, or components are modified before the product is deployed.

In a survey conducted by company Blackduck among 540 security leaders, 65% reported experiencing at least one software supply chain attack in the past year, demonstrating that embedded firmware and tooling can be high-impact vectors for compromise. For each adversary class, concrete attack paths should be identified that genuinely intersect with the existing code, without introducing controls that unnecessarily degrade optimal performance.

The outcome of a well-constructed threat model is a set of security requirements that can be verified in practice. These include:

  • a strategy for disabling or restricting debug access,
  • an update mechanism protected against rollback,
  • an MPU configuration that separates code and data,
  • and key management rules.

If a requirement cannot be verified or enforced, it does not belong in the threat model.

Hardware-anchored chain of trust and deterministic access control at startup

If threat modeling defines which components cannot be trusted and under what conditions, the chain of trust is the mechanism that enforces those assumptions during system startup. The chain of trust in bare-metal systems is a sequence of boot stages in which each stage is allowed to start the next one only after specific security conditions are met. The starting point is the Root of Trust: immutable code stored in ROM (or protected mask ROM) together with a mechanism for storing the public key or its hash (for example in eFUSE or OTP memory). The first stage (ROM/FSBL) should perform only the minimal initialization required to verify the next image. This includes:

  • setting up memory mapping,
  • disabling or locking debug interfaces,
  • stabilizing access to flash memory,
  • and configuring exception handling policies.

It then verifies the image signature, ensuring both integrity and authenticity, and enforces anti-rollback protection using a monotonic version counter stored in OTP or secure non-volatile memory. Without this, an attacker can revert the device to an older, vulnerable firmware version. If there is unauthorized physical access, even these security mechanisms could be bypassed.

It is important to distinguish between verification and measurement. Verification prevents unauthorized code from executing. Measurement records cryptographic measurements of boot stages (for example component hashes) for use in later policy enforcement or attestation. Without a secure update path, key rotation, and a revocation mechanism, the chain of trust becomes a one-time check at boot. It no longer maintains security throughout the product lifecycle and leaves devices exposed as they age into outdated software baselines.

Discover the Best Hardware Design Companies in 2026
Not sure which hardware design partner to choose? We’ve analyzed and ranked the best companies across the globe based on expertise, technology, quality certifications, and client reviews.

View Complete Ranking →

Secure boot and applications running: The gap between verification and runtime safety

Secure Boot primarily protects the continuity of code origin and integrity during system startup. Its core function is a “run / do not run” decision based on cryptographic verification of the next boot stage or firmware image. In practice, this provides resistance against binary replacement in external memory and unauthorized updates. It can also mitigate certain supply-chain attacks, provided that keys and the production process are properly controlled. Secure Boot typically also enforces versioning policy. Without anti-rollback protection, an attacker does not need to break a signature. Reverting the device to an older, legitimately signed but vulnerable firmware version is sufficient.

What Secure Boot does not protect is runtime safety. If a signed firmware contains memory-safety bugs, a vulnerable parser, an incorrect privilege model, or misconfigured MPU settings, it remains a “validly booted” exploit. Secure Boot also does not defend against physical attacks such as fault injection. It also does not replace the need for a secure update path, key rotation, and a key revocation mechanism. Nor does it eliminate the need for regular security audits that assess the interaction between boot policy and runtime behavior.

Firmware vulnerabilities as a real security problem

Firmware vulnerabilities in bare-metal systems primarily arise from the fact that critical system functions are implemented within a single, privileged image. The most common issues involve memory safety. These include:

  • buffer overflows,
  • out-of-bounds memory access,
  • errors in pointer handling.

In a bare-metal environment, such flaws do not lead to privilege escalation because privileges are already maximal. Gaining control over the program’s execution flow is sufficient.

Code paths that process external input are particularly exposed. These include communication frame parsers, radio stacks, and firmware update mechanisms. In these areas, attacker-controlled data is fed directly into code executing with the highest privileges. An additional source of security risk comes from DMA-capable peripherals, which can modify memory without CPU involvement. If a clear protection policy does not constrain them, they can bypass even correctly written code.

Effective defense requires reducing the attack surface. This involves minimizing parsing code and enforcing explicit input validation. It also requires applying strict C coding standards and conducting tests focused on attack paths rather than solely on functional correctness.

Memory Protection Unit as a Bare Metal Solution: Isolation or architectural compromise?

If we accept that firmware bugs are inevitable, the next step is to determine which boundaries the system architecture can still enforce. The MPU (Memory Protection Unit) is a mechanism that enforces simple access rules for memory regions without the cost and complexity of a full MMU. It allows regions to be defined with attributes such as read-only, executable or non-executable, and privileged-only access. In bare-metal systems, the MPU is often the only tool available to mitigate the impact of memory-related bugs. However, it does not provide the process-level isolation found in systems with virtual memory.

In practice, the greatest risk lies in configuration. The number of regions is limited and typically requires power-of-two alignment, which encourages overly broad regions and protection gaps. A common anti-pattern is leaving all RAM as a single RWX region because it simplifies debugging. Another issue is DMA: the MPU controls CPU access, but not necessarily peripheral transfers, so without additional bus-level constraints, “protected” sensitive data can be modified outside the CPU’s control. The MPU is therefore a compromise. It can meaningfully reduce the blast radius of bugs, but only if region policies are aligned with the threat model and tested under failure conditions.

Trusted Execution Environment: A costly response to the lack of isolation

A Trusted Execution Environment (TEE) in embedded systems introduces a hardware-enforced separation of execution between two domains: the normal world and the secure world. This mechanism restricts access to certain system resources (such as memory regions, peripherals, and registers) to the secure context only. As a result, even if the main firmware is compromised, code running inside the TEE can preserve its integrity and confidentiality. When and why is it worth using a TEE in embedded systems?

The method of context switching is critical. Calls into the TEE are performed via special instructions (for example, Secure Monitor Call) or exceptions (such as Secure Monitor Exception) that switch the execution domain. Each such transition creates a trust boundary, meaning a point where data from an untrusted world enters privileged code. If this interface is not minimal and well defined, the TEE begins to accumulate the same classes of bugs it was intended to mitigate.

TEE also affects the overall system architecture. It increases the number of system states, complicates interrupt handling, and makes debugging more difficult. Industry studies on secure software engineering (including reports from the National Institute of Standards and Technology and the SEI CERT program) consistently show that defect density increases with architectural complexity and state-space growth, particularly in low-level C-based systems. In embedded environments, where memory-safety issues account for approximately 70–80% of reported firmware vulnerabilities according to aggregated CVE analyses, increasing state transitions and privileged entry points statistically increase exposure.

In practice, a TEE improves security only when the protected scope is narrow and communication is limited to a small set of strictly controlled operations. Otherwise, it becomes an expensive source of new vulnerabilities.

Integration of Secure Boot, MPU, and TEE

The integration of Secure Boot, MPU, and TEE makes sense only when these mechanisms form a coherent chain for enforcing security policies, rather than acting as independent “security layers.” Secure Boot determines which code is allowed to run, but it does not yet impose execution boundaries. Those boundaries are defined by the MPU, which should be configured as early as possible and maintained consistently across all boot stages. In practice, this means separating code (RX), data (RW), and stack regions, and enforcing the NX attribute for areas that should never be executable.

TEE provides isolation for secrets, but only if it takes control of critical resources. Keys must not “leak” into the normal world, and the call interface must be minimal and resilient to parameter validation errors. A common integration failure occurs when Secure Boot correctly verifies the image and the MPU remains in a debug-friendly configuration (for example, broad RWX regions). In such cases, the TEE may be used as a key store, while DMA or uncontrolled buffers in the normal world still allow manipulation of input data to the secure world. True coherence requires fault-oriented testing:

  • rollback attempts,
  • resets during updates,
  • deliberate attempts to violate MPU policies and TEE interfaces.

Only when these mechanisms are aligned under a model of shared responsibility across boot, runtime, and update phases does the architecture achieve meaningful resilience.

If you’re curious how bare metal programming works, read our development guide:

How Bare Metal Programming Works: Development Guide

Data security in constrained devices: When correct cryptography still fails

Cryptography in bare-metal systems serves as a mechanism for authorizing system state, not as a “magic protection layer.” Its primary use is the signing of boot stages and firmware updates, ensuring that the device accepts only images originating from a trusted manufacturing process. In this model, what matters is not only signature verification but also the strict enforcement of version policy. Without anti-rollback protection, an attacker does not need to forge an image. Reverting the device to an older, correctly signed version that contains a known vulnerability is sufficient. Effective protection, therefore, requires a monotonic version counter stored in eFUSE/OTP or other secure non-volatile memory, and a clear binding between the image and its version.

The greatest cryptographic risk lies in key engineering rather than in algorithms. On the vendor side, the private signing key must be protected through organizational controls such as HSMs, access control, and auditing. On the device side, the trusted public key or its hash must be anchored in hardware, not stored in writable flash. In practice, revocation and key rotation mechanisms are also necessary, because key compromise is a realistic event, not a theoretical one. Equally important, cryptography does not compensate for missing isolation. If the normal world can manipulate input data to the verifier or to a TEE (for example via DMA), “correct” cryptography becomes part of a chain that can still be bypassed. This risk is amplified in systems where significant computing power is not available to implement runtime anomaly detection.

Coding standards as a security mechanism

MISRA C influences firmware security by restricting those aspects of the C language that make program behavior difficult to analyze unambiguously at runtime. In bare-metal systems, every piece of code executes with full privileges, so errors caused by undefined behavior have immediate consequences. Examples include implicit integer type conversions, dependence on the size of int, or pointer arithmetic that goes beyond object boundaries. MISRA eliminates such constructs by enforcing explicitness and predictability of operations.

This is particularly important in low-level code. Interrupt handlers, peripheral drivers, and data parsers operate on raw buffers and hardware registers. In these areas, even small semantic ambiguities can lead to memory corruption or loss of control over program flow. MISRA reduces this risk, but it does not eliminate it. It does not protect against:

  • a flawed division of responsibilities between modules,
  • incorrect MPU configuration,
  • or vulnerable TEE interfaces.

Its real value emerges only when it is combined with static analysis, code reviews, and tests focused on attack scenarios rather than solely on functional correctness.

InTechHouse – A strategic approach to bare metal server security

In practice, an effective bare-metal security strategy is about balance. Secure Boot and Trusted Execution Environments do not solve “all security problems,” but they clearly define boundaries of trust and responsibility already at the system boot stage. This enables a shift from reactive vulnerability patching to proactive design of mechanisms that limit the impact of errors, software compromise, and unforeseen attack scenarios.

See How We’ve Helped Companies Like Yours
Explore our portfolio of successful bare metal projects across automotive, medical devices, and IoT. Real case studies with technical details and measurable results.

Browse Our Projects →

If you are facing a technological decision where product stability, risk control, and long-term scalability are at stake, InTechHouse offers practical support rather than empty promises. The company combines deep engineering expertise with a clear understanding of the business consequences of technical decisions. We operate where architecture, accountability, and knowledge transfer matter, not merely where code delivery is expected. If you care about making conscious, well-informed technology choices, InTechHouse is the right choice. Call us and schedule a free consultation with our experts.