October 17, 2025

Missing Mitigations: Inside The Security Gap in UEFI Firmware

By Binarly REsearch

Introduction 

Software mitigations play a critical role in the quest to secure the digital world. Shortly after the discovery and the rise of buffer overflows in the 90s, mitigations were introduced in the software ecosystem and eventually made their way into virtually any piece of software we run on our devices: from browsers to web servers, from OS kernels to userspace applications. 

Mitigations are typically designed to address one or more classes of vulnerabilities, making their exploitation more difficult. For example, while exploiting a stack overflow without any deployed mitigation is straightforward, the presence of properly implemented stack canaries requires chaining additional vulnerabilities or leveraging more complex techniques to bypass this protection. 

To date, numerous mitigations have been proposed and implemented. For example, Control Flow Integrity (CFI) ensures that the execution flow follows legitimate paths and cannot be arbitrarily manipulated by attackers. Another example are randomization-based mitigations that load code and data at random addresses, making it difficult for attackers to target predictable memory layouts in their exploits. Over the past 20 years, mitigation techniques have steadily evolved, driven by efforts from both academia and industry. This progress has followed a familiar "cat-and-mouse" pattern in computer security: attackers develop ways to bypass defenses, and defenders respond by improving them.

Today, mitigations are very common in operating systems and software applications, but what about firmware and specifically the UEFI firmware ecosystem

This research answers this question by setting out with two main goals:

  • The first is to educate the firmware community on which mitigations are available and how they work, based on the EDK2 reference implementation. This will allow the community to understand the strengths, the limits and the drawbacks of each mitigation. 
  • The second goal of this research is instead to evaluate the prevalence of mitigations in the UEFI firmware ecosystem. To achieve this goal we use the Binarly Transparency Platform to scan an extensive dataset of firmware images used in thousands of consumer and enterprise devices. The dataset contains 5,477 recently-released firmware images, in total covering over 2.3 million UEFI modules

The results of this research paints a worrisome picture of the UEFI ecosystem: only a few devices have basic mitigations enabled by default, while the vast majority lack even the most fundamental protections (e.g. stack canaries).

Taxonomy of  Mitigations in UEFI firmware

UEFI firmware is a critical component of modern computing. Given its privileged execution context and wide attack surface, securing UEFI firmware is essential to prevent compromise that could affect the entire system. To address these risks, a variety of mitigations have been developed over the years, reducing exposure to vulnerabilities at different layers of the firmware stack and throughout its lifecycle. 

The following taxonomy organizes UEFI firmware mitigations according to the types of threats they address:

  • Memory safety mitigations include techniques designed to prevent memory corruption or make the exploitation of software bugs more difficult. Since UEFI firmware is written in an unsafe language, it is prone to common vulnerabilities found across the software ecosystem, such as buffer overflows and use-after-free errors. Mitigations in this category include stack canaries, control-flow integrity (CFI), shadow stacks, heap hardening and Address Space Layout Randomization (ASLR).
  • Microarchitectural-level mitigations address vulnerabilities rooted in the CPU microarchitecture. In this context, UEFI firmware plays a dual role: it must both ensure that updated microcode is applied to mitigate hardware-level threats and ensure that its own code is protected against such microarchitectural-level attack vectors. Examples of mitigations include microcode updates to address Spectre and Meltdown, and the insertion of speculative execution barriers (e.g. LFENCE, CPUID).
  • UEFI boot security mitigations refer to measures designed to protect the integrity of the boot process and maintain the chain of trust. These measures ensure that the system starts in a known-good state and that only authorized code is executed during early initialization. Key mitigations include Intel Boot Guard, Secure Boot and TPM-based measured boot.
  • SMM-focused mitigations: include mitigations designed specifically to protect System Management Mode. This category includes mitigations that enforce the integrity of SMM code, memory and execution isolation, and privilege separation, preventing attackers from compromising SMM or leveraging it to escalate privileges. Examples of mitigations in this category are SMI Transfer Monitor (STM), Intel PPAM, and SMM call-out protection (SMM_CODE_CHK_EN).
  • BIOS-focused mitigations include measures aimed at protecting the core firmware image and runtime environment. These mitigations ensure that the BIOS or UEFI firmware cannot be tampered with by attackers. Examples of mitigations in this category include BIOS write-protection mechanisms such as flash descriptor locks, BIOS region write-protection (BIOSWE, BLE), SMM-based SPI flash write controls (SMM_BWP) and early peripheral and DMA access restrictions using technologies such as VT-d or IOMMU.  
Overview of selected UEFI firmware mitigations analyzed in this research.

Given the broad scope of UEFI firmware security, this research focuses on three key categories: memory safety mitigations, microarchitectural-level mitigations, and UEFI boot security mitigations. For each category, we selected a representative subset of mitigations:

  • Memory safety mitigations: stack canaries, stack guard, control-flow integrity (CFI), and no-execute (NX) protections.
  • Microarchitectural-level mitigations: microcode updates and RSB stuffing.
  • UEFI boot security mitigations: Intel Boot Guard, outdated forbidden signature database, and UEFI Platform Security Flags.

These categories capture some of the most critical aspects of firmware security that directly affect system integrity. The Binarly Transparency Platform (BTP) can detect and report the presence or absence of these mitigations, enabling assessment of potential security gaps in UEFI firmware.

Memory Safety Mitigations

Stack Canaries

Stack canaries were introduced in the late 1990s and are considered one of the earliest, if not the first, software mitigation. This mitigation protects against buffer overflow attacks by placing a value, known as a stack canary or stack cookie, between local variables and control data (such as, the return address) saved on the stack. During the function epilogue, the canary value is checked. If it has been altered, this indicates a buffer overflow has occurred, and execution is terminated to prevent further exploitation.

This mitigation is available virtually everywhere in the software ecosystem due to its implementation simplicity and minimal overhead. Despite this, stack canaries have been enabled in the reference implementation for most toolchains and architectures only very recently, in February 2025. 

Before this recent change, stack canaries were disabled in the EDK2 reference implementation for all toolchains, with the only exception being the GCC toolchain when compiling for ARM targets. All other toolchain definitions explicitly disabled stack canaries by using the GCC option “-fno-stack-protector or the Visual Studio option “/GS-”. The older ARM-based implementation used static canaries that don’t change at runtime, while the newer implementation uses randomized values.

Stack Guard

The UEFI Stack Guard mitigation allocates a guard page at the bottom of the stack to prevent any linear access beyond the stack’s end. This guard page is marked as “not present” in the page table, so any read or write access triggers a page fault. The purpose of this mitigation is to prevent the stack from growing into adjacent memory regions and corrupting them. While Stack Guard was designed with debugging in mind, it can also be employed as mitigation.

The reference implementation includes support for Stack Guard during the PEI and DXE phases as well as for System Management Mode (SMM). Stack Guard for DXE phase is implemented by setting the memory attribute EFI_MEMORY_RP on the page at the bottom of the stack. 

This mitigation can be enabled during PEI and DXE by setting the PcdCpuStackGuard option, which is disabled by default in the reference implementation. In contrast, Stack Guard for SMM is controlled by the flag PcdCpuSmmStackGuard and is enabled by default

Control-flow Integrity (CFI) 

Control-flow integrity is another widely used mitigation designed to prevent attackers from hijacking the execution flow. Over the past decade, numerous designs and flavors of CFI have been proposed, each with unique strengths and limitations. A recent WOOT paper systematized actively used CFI schemes and explored their effectiveness. The core idea behind CFI is to validate backward and forward control flow transfers–such as indirect calls and function returns–to ensure that the execution follows only legitimate paths. When enabled, this mitigation can prevent exploits based on code injection or return-oriented programming. 

EDK2 supports Intel’s Control-flow Enforcement Technology (CET) as CFI mitigation. CET can detect corruptions of the return address stored on the stack, since it stores a copy of the return address on a secondary stack, called shadow stack, which cannot be tampered with by an attacker. On function return, the return address stored on the shadow stack is compared with the address stored on the “normal” stack to ensure the integrity of the stack. 

Shadow stacks are particularly useful in protecting against Return Oriented Programming (ROP) exploits. To protect against Jump-Oriented-Programming (JOP) and Call Oriented Programming (COP), the CET technology uses Indirect Branch Tracking (IBT). With support from the compiler, IBT marks all valid targets of indirect control flow transfers (i.e. calls and jumps) with the endbr instruction. At runtime, an exception is raised if a control-flow transfer does not land directly on an endbr instruction. 

The reference implementation contains support for CET shadow stacks, which can be enabled by setting the PcdControlFlowEnforcementPropertyMask. However, the reference implementation is designed only for SMM modules, meaning that SEC, PEI or DXE modules are not safeguarded. This mitigation is disabled by default, even on systems supporting CET. Regarding IBT, the EDK2 toolchain definitions lack the necessary flags to instruct the compiler to insert “endbr” instructions, meaning that compiled modules will not contain the instructions needed by IBT. 

ARM has a mitigation similar to IBT called Branch Target Identification (BTI). EDK2 has preprocessor macros for instrumenting hand-written ARM assembly functions with the BTI instruction (“bti c”), which marks targets of indirect function calls. However, the EDK2 toolchain definitions lack the flags for instrumenting compiled code with BTI instructions (i.e. -mbranch-protection).

No eXecute (NX)

The No eXecute (NX) protection, also known as Data Execution Prevention (DEP), is a security feature that prevents execution of code stored in memory regions intended for data. Any page that does not contain executable code is marked as non-executable in the page table, effectively stopping any attempt to execute malicious code, such as shellcode, stored there. This mitigation is often used in conjunction with other mitigations that prevents writes to memory regions containing code. 

The reference implementation offers three different PCD values to fine-tune this mitigation: PcdImageProtectionPolicy, PcdDxeNxMemoryProtectionPolicy and PcdSetNxForStack. The first option, PcdImageProtectionPolicy, determines whether a DXE module should have its code section marked as read-only and its data section as non-executable. The determination is done depending on the module’s source, which can either be a firmware volume or an unknown source. The option PcdDxeNxMemoryProtectionPolicy allows instead to set certain memory regions types (such as EfiLoaderData) as non-executable. Finally, PcdSetNxForStack allows setting the stack as non-executable

For X86, PcdImageProtectionPolicy enables protection only for images loaded from firmware volumes, excluding those from unknown devices (such as the EFI System Partition). Both PcdDxeNxMemoryProtectionPolicy and PcdSetNxForStack are disabled by default. As a result, the reference implementation prevents execution from the data section and modification of the code section only for PE images loaded from firmware volumes. 

For ARM targets, PcdImageProtectionPolicy is enabled also for unknown sources and PcdDxeNxMemoryProtectionPolicy correctly enables NX for all non-code regions, including the stack. 

Microarchitectural-Level Mitigations 

Microcode Updates

UEFI firmware images also include updates for the CPU microcode. The microcode breaks down complex instructions into ones that are more easily implemented in hardware. From a security standpoint, the microcode includes mitigations for various microarchitectural weaknesses, such as transient execution attacks. As a result, it is essential for UEFI firmware to always be shipped with the latest revision of the microcode.

The reference implementation has support for microcode updates. This includes the definition of the structures related to microcode which are used for parsing and loading microcode updates.

RSB Stuffing

The Return Stack Buffer is used by the CPU to predict the target of return addresses. Underflows on this buffer can be exploited to mount microarchitectural attacks. When the RSB stuffing mitigation is enabled, dummy return addresses are pushed into this CPU buffer to overwrite potentially malicious entries. This prevents attackers from manipulating the RSB to redirect control flow and achieve arbitrary speculative code execution.

EDK2 provides assembly macros for stuffing the RSB with dummy addresses. These macros are used to protect SMM code, and are inserted just before returning from SMM with the RSM instruction, to mitigate potential speculative attacks. The original patch implementing this mitigation was developed by Intel and contributed to the EDK2 repo in August 2018

This mitigation is enabled by default.

UEFI Boot Security Mitigations 

Intel Boot Guard

Intel Boot Guard is a hardware-based security feature that ensures the integrity of the system's firmware by verifying several cryptographic signatures. It allows to establish the root of trust within the firmware, since it protects against unauthorized tampering.  

There are several components used by Boot Guard that require verification, for example the Key Manifest (KM) or the Boot Policy Manifest (BPM). These components’ signatures are verified by the CPU using different cryptographic keys, some of which are fused into the platform hardware, while others are instead stored in the firmware itself. 

The reference implementation doesn’t include any support for Intel Boot Guard, as this is a proprietary feature implemented by Intel.

Outdated Forbidden Signature Database (dbx)

The Forbidden Signature Database (dbx) is a crucial component of UEFI Secure Boot. This database contains the cryptographic signatures and certificates associated with compromised or vulnerable UEFI modules.

While each vendor can customize this database, Microsoft maintains a publicly available list of all known threats that should be included in every dbx. Because Secure Boot represents a last line of defense, It is essential to keep the dbx updated, as failing to do so can result in firmware-level threats to be deployed on a target system.

The reference implementation has complete support for parsing the dbx and for using this information to verify any UEFI images, such as bootloaders, before execution.  

UEFI Platform Security Flags (uefiplat.cfg)

The uefiplat.cfg file is found in UEFI firmware based on Qualcomm reference code for ARM devices, such as the Microsoft Surface or the Lenovo Thinkpad X13s. As we previously documented, this file contains different firmware configuration items. Some of these items are simply related to the device, such as MemoryMap which stores a list of memory mappings. The SecurityFlag item is instead focused on security features like Secure Boot, measured boot and Trust Zone. Finding this component in a firmware image is straightforward, as it’s stored in a Raw Section with a known GUID.

The reference implementation doesn’t include any support for the uefiplat.cfg file, as this is a proprietary security feature implemented by Qualcomm in their eXtensible BootLoader (XBL).

Mitigations Summary

In the previous section we explored some of the most common mitigations and their implementation within the EDK2 reference code. In summary, EDK2 contains a reasonable number of software mitigations and allows firmware developers to customize them. However, we identified two main areas of concern:

  1. Only a few mitigations are enabled by default, in particular for X86, meaning that OEMs and device vendors have to manually enable and validate them
  2. Several mitigations that are commonly found in the software ecosystem are either missing from the reference implementation or are marked as debug features.

The most significant example of missing mitigation is Address Space Layout Randomization (ASLR), a low-overhead mitigation that is widely used in the software ecosystem. Although a prototype implementation for ASLR was developed in the SecurityEx repository, this standalone project was never ported to the main EDK2 repository.

Other mitigations, such as Heap Guard, are implemented in the reference implementation but discouraged to use. This mitigation is designed to detect heap overflows by placing guard pages between heap pages or heap pools. 

Despite its effectiveness, this mitigation is marked as a debug-only feature, with a warning stating that it “should not be enabled in product BIOS”. As we previously reported, this mitigation alone would have been sufficient to prevent our PoC for LogoFAIL.

Adoption of Mitigations in the Wild

In this section, we look closer at the mitigations observed in the wild, with a particular focus on different implementations of stack canaries. We chose to focus on stack canaries because they represent one of the most basic yet effective security measures, and because they are the only mitigation present in the reference implementation that is also commonly customized by firmware vendors. 

Following this, we present the results of scanning over 5,000 firmware images using our Binarly Transparency Platform. These results represent a first in the industry and provide a clear view of the current state of mitigation adoption within the UEFI ecosystem.

A tangled supply-chain case study on Stack Canaries

In this section, we will look at the different implementations of stack canaries that we found in the wild. This will provide a new perspective on how different vendors implemented a well-known security defense. An important note is that these implementations were all identified automatically by our platform, which is able to report (the lack of) mitigations in scanned firmware.

Reference Implementation

The current implementation of dynamic stack canaries present in EDK2 was only recently added in February 2025. Since this implementation is very new, it’s likely not present in real-world firmware. For this reason, we’ll focus on the previous implementation of stack canaries, which was introduced in 2014.

As previously discussed, this implementation is currently enabled only for ARM devices. Even after reviewing the related pull requests and discussions, the rationale behind this decision remains somewhat unclear to us. Additionally, we noticed that the canary value is set to a fixed, predictable value (0x0AFF), rather than being randomized, which raises some concerns from a security perspective. 

This choice significantly limits the effectiveness of the implementation in preventing most buffer overflow attacks targeting firmware. Since the canary value is fixed and predictable, an attacker could easily include it in their payloads, thereby bypassing the intended protection. While this implementation does not offer meaningful security benefits, the patch discussion suggests that the implementation was intended as a security feature rather than a debugging one. The 0x0AFF constant was chosen because it contains “NULL (will terminate strings), LF, and -1” with a goal to “contain read based overruns”, an attack vector that is however not present in the UEFI firmware.  

data:0000000000010000 __stack_chk_guard    DCQ 0xAFF

int64 sub_3504() {
  // Setting the canary
  stack_canary = __stack_chk_guard;   
  ...

  // Checking the canary
  if ( stack_canary != __stack_chk_guard)
    __stack_chk_fail();
  ...
}

The reference implementation of stack canaries was found in many ARM devices from Gigabyte, Supermicro, HPE, Dell and Lenovo. However, a closer look at scan results from the Binarly Transparency Platform revealed that only a limited number of modules within these images are protected with stack canaries. 

The decision to protect a module does not appear to be based on the module’s security relevance, such as whether it handles untrusted input, but rather seems to depend on the supply-chain partner responsible for compiling it. For instance, the Supermicro G1SMH firmware includes 19 modules protected by canaries (e.g., GPURecovery and RASBaseServices), all of which appear to be supplied by NVIDIA. The protected modules are mostly device drivers, while other security-critical modules, such as Ip6Dxe or TcpDxe, both of which were impacted by the PixieFail vulnerabilities, are left unprotected.

Another interesting finding is that some modules ship with a __stack_chk_fail function (i.e. the function that is called when a canary mismatch is detected) that only returns without taking any action. This behavior effectively nullifies the purpose of the stack canary mechanism, rendering the protection ineffective

Implementation of __stack_chk_fail which effectively does nothing.
   Functional implementation of __stack_chk_fail that raises a breakpoint or enters a dead loop depending on the DebugPropertyMask PCD value.

Qualcomm Implementation

A second custom implementation of stack canaries, which we already covered in our cross-silicon exploitation research, is developed by Qualcomm for ARM devices. This implementation uses the UEFI Configuration Tables and is initialized at a module’s entry point. As shown in the next snippet, the entry point function checks for the presence of the custom configuration table with GUID B898D8DC-080A-40F7-99E3-31627B806A5A. If this table is found, the firmware retrieves the canary value stored within the table. When the table is instead not found, the function will generate a new canary by calling the UpdateCanary() function.

EFI_STATUS ModuleEntryPoint(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
  UINTN NumberOfTableEntries; // x2
  EFI_CONFIGURATION_TABLE *ConfigurationTable; // x3
  __int64 v4; // t1
  EFI_STATUS result; // x0
  EFI_HANDLE ImageHandleCopy; // [xsp+38h] [xbp-18h]

  if ( ImageHandle )
  {
    ImageHandleCopy = ImageHandle;
    if ( SystemTable
      && LOBYTE(SystemTable->Hdr.Signature) == 73
      && BYTE1(SystemTable->Hdr.Signature) == 66
      && BYTE2(SystemTable->Hdr.Signature) == 73 )
    {
      NumberOfTableEntries = SystemTable->NumberOfTableEntries;
      ConfigurationTable = SystemTable->ConfigurationTable;
      while ( NumberOfTableEntries )
      {
        --NumberOfTableEntries;
        v4 = *&ConfigurationTable->VendorGuid.Data1;
        ++ConfigurationTable;
        if ( v4 == *&QCOM_CANARY_CONFIGURATION_TABLE_GUID_PTR->Data1 )
        {
          *gCanaryPtr = ConfigurationTable[-1].VendorTable;
          goto LABEL_12;
        }
      }
      UpdateCanary();
      SystemTable->BootServices->InstallConfigurationTable(QCOM_CANARY_CONFIGURATION_TABLE_GUID_PTR_0, gCanary);
    }
    else
    {
      UpdateCanary();
    }
LABEL_12:
    ImageHandle = ImageHandleCopy;
  }
  Main(ImageHandle);
  return result;
}

In our dataset we found two implementations of the UpdateCanary() function: one returning a  hardcoded value (0xc0c0c0c0) and another that creates a random canary using the ARM Secure Monitor Call (SMC). While the first implementation suffers from the same problems discussed in the previous section, the second implementation is strong since it uses non-predictable canaries. 

The Qualcomm implementation of stack canaries was found in several ARM-based firmware, such as the Dell XPS 9345, the Lenovo Yoga Slim 7 and the Microsoft Surface. Interestingly, some firmware contains both the “reference implementation” and the “Qualcomm implementation”, reinforcing the idea that modules were compiled by different supply-chain partners. This further highlights the fragmented nature of firmware development, where security features like stack canaries are applied inconsistently depending on the origin of each module.

Another wild X86 implementation appears

Finally, our platform also identified a third implementation of stack canaries for x86. After some research we discovered that this implementation is the one used in the iPXE network bootloader. In this implementation the random canary value is generated by combining together the value of the ImageHandle function parameter, a stack address, a random static value (qword_35760) and the system clock (as returned by rdtsc instruction):

__int64 __fastcall efi_stack_cookie(__int64 ImageHandle)
{
  __int64 StackAddress; // [rsp-8h] [rbp-8h] BYREF

  return (qword_35760 ^ __ROL8__(__ROL8__(__ROL8__(ImageHandle, 16) ^ &StackAddress, 16) ^ __rdtsc(), 16)) << 8;
}

This implementation can be found in the iPXE module included in some HPE firmware images for x86 and ARM servers.

Prevalence of Mitigations

In this section we provide the first-ever overview on the usage of mitigations in the UEFI firmware ecosystem. To do so, we leverage a comprehensive dataset of 5,477 recently-released firmware images. The dataset includes firmware released by all major device vendors (Acer, Asus, Dell, Fujitsu, Gigabyte, HP, HPE, Intel, Lenovo, MSI, Samsung and Supermicro) and by all IBVs (AMI, Insyde, Phoenix) providing an accurate overview of the current state of the UEFI ecosystem. When unpacked, these firmware images contain over 2.2 million unique UEFI modules.

This analysis was done automatically by our Binarly Transparency Platform. The platform detects each mitigation by matching some specific artifacts that are present in the binary image under analysis, ensuring high-confidence results with extremely low false positives.

Memory Safety Mitigations

Stack Canaries

Despite being one of the lowest-overhead and easiest-to-implement mitigations, stack canaries are adopted at an alarmingly low rate in the UEFI ecosystem. 

Out of more than 2.3 million analyzed modules, only 2,674 use stack canaries, which corresponds to an adoption rate of just 0.12%. At the firmware image level, canaries were detected in only 52 out of 5,477 images, resulting in a 0.94% adoption rate. When excluding the iPXE bootloader, which implements stack canaries but is only used in specific network-boot environments, this figure drops further to 0.36%

In addition, except for the iPXE-related modules, all the firmware with stack canaries is intended for ARM-based devices. This means that not a single x86 firmware ships with this basic mitigation implemented.

The new reference implementation for dynamic stack canaries on x86 appears very promising. However, we anticipate that widespread adoption within the x86 firmware ecosystem may still take several months, if not years.

Stack Guard

The analysis implemented in the Binarly Transparency Platform detects Stack Guard for DXE on the x86 architecture. As we previously reported, this mitigation is disabled by default in the reference implementation

The effects of this decision can be clearly seen in our dataset: only 332 images have stack guard enabled, meaning that more than 94% of firmware ships with this protection disabled.  

Control Flow Integrity (CFI) 

To detect the presence of CFI technology in UEFI firmware, the platform disassembled each UEFI module and searched for the X86 Indirect Branch Tracking (IBT) instructions (endbr32 and endbr64) and for ARM Branch Target Identification (BTI) instruction (bti). 

The adoption of this mitigation remains limited: only 1140 modules contain X86’s IBT instructions, and just 336 are instrumented with ARM’s BTI protection. The protected modules are often of limited relevance from a security perspective, as they all appear to be device drivers (such as the SecureBIOCamera_Sonix module and the AX88179 controller found in Lenovo and Acer firmware) which are unlikely to be targeted by attackers. 

Moreover, all of these modules operate in the DXE phase, whereas the EDK2’s integration of Control-flow Enforcement Technology (CET) currently applies only to SMM code, not DXE. For these reasons, we speculate that these instances are not deliberate attempts to apply CFI protections to UEFI firmware, but rather resulting from different build environments used by third-party entities within the firmware supply chain.

No eXecute (NX)

No eXecute is another mitigation that is very popular in the software ecosystem and that has been integrated on different platforms and systems. However, in the UEFI ecosystem it remains quite often disabled and only 9.38% of the analyzed firmware set a correct memory protection policy with the PcdDxeNxMemoryProtectionPolicy option. 

The reference implementation properly sets this option only for ARM firmware. This choice had positive effects in terms of adaption: all ARM firmware in our dataset properly set this mitigation.

On the other hand, virtually every firmware in our dataset sets PcdImageProtectionPolicy to 2, meaning that all images loaded from a firmware volume will have their code and data section properly marked as read-only and non-executable, respectively. In addition, some vendors such as Dell, set this option to 3, so images loaded from unknown devices (such as bootloaders) are also protected in a similar way. 

However, we discovered an important catch related to this mitigation that is only briefly noted in a configuration file: for this mitigation to work, the section alignment specified in the PE header must match the EFI page size (0x1000). In other words, if the alignment doesn’t match the page size, the mitigation is not applied. 

We found that 68% of the analyzed DXE modules don’t respect this requirement. As a result, all these modules will have writable code sections and executable data sections. A possible explanation for this mismatch is that most tool definitions in the reference implementation lack the necessary directives to configure the compiler to set the section alignment to the required value.

Microarchitectural-Level Mitigations 

Microcode Updates

Up-to-date microcode ensures that a system is not vulnerable to known transient execution attacks. Microcode updates are released by CPU vendors, such as Intel and AMD, and shared with firmware vendors so they can be included in firmware updates. 

Our analysis shows that 88% of firmware images ship with an outdated version of the microcode and 71% of images ship with a microcode affected by a vulnerability

Outdated microcode opens the doors to many common transient execution vulnerabilities, like the Gather Data Sampling attack (GDS) (also known as “Downfall”) and MMIO Device Register Partial Write (tracked by INTEL-SA-00615). It also leaves systems susceptible to newer threats, such as the recent Entrysign (CVE-2024-56161) which exploits flaws in the AMD microcode signature verification.

While microcode can be updated by other means, such as from the operating system, firmware updates should still ship with the latest available microcode to ensure that systems are always protected against transient execution attacks regardless of OS updates. 

RSB Stuffing

The mitigation against Return Stack Buffer underflows was added to the reference implementation in August 2018 and has been enabled by default since. RSB stuffing has a negligible impact on the return from SMM, done with the rsm instruction. Our analysis focuses on X86 firmware, and in particular on the PiSmmCpuDxeSmm module which contains both the entrypoint and the exit point for SMM. 

Despite the negligible overhead of RSB stuffing, we found that 13% of these firmware images completely lack this mitigation, leaving every rsm instruction unguarded. The 37% of the firmware has only partial protection, with at least one RSM lacking RSB stuffing protection.

UEFI Boot Security Mitigations

Intel Boot Guard

As we extensively documented in the past, several public data leaks affected the UEFI industry. These leaks, combined with poor key management, resulted in multiple Boot Guard private keys leaking to the public. Our analysis focuses specifically on this problem by checking whether the RSA keys used in the Key Manifest (KM) or in the Boot Policy Manifest (BPM) were leaked or not. 

In total, we found 338 firmware using a leaked KM key and 342 firmware using a leaked BPM key. Overall, there are 345 firmware (6.3%) using at least one leaked key. This opens the door to attackers for firmware implantations, as by using these leaked keys they can modify, sign and flash a malicious firmware image.

We also checked for mismatches between the KM and BPM that occur when the RSA key hash contained in the KM signed area doesn’t verify the BPM public key. This represents a problem because it signals that Boot Guard is unverified and might be not enforced during boot. 

In total, we found 189 firmware where this mismatch happens.

Outdated Forbidden Signature Database (dbx)

The Outdated Forbidden Signature Database ensures that UEFI firmware blocks the execution of untrusted components that can be abused to bypass Secure Boot and other firmware protection mechanisms. Microsoft tracks these untrusted components and offers a revocation list, which currently includes 430 signatures for X86-64.

We found that only ARM-based firmware consistently ships with the latest dbx, whereas among x86 firmware, Framework is the only vendor that includes the latest revocation list. The remaining firmware ships with an outdated dbx, which in most cases is missing hundreds of signatures

This leaves these devices open to attacks against Secure Boot, including our recently disclosed CVE-2025-3052.  Similar to microcode updates, the dbx can also be updated from the OS. However, including an up-to-date dbx database directly into the firmware ensures that all systems are resilient against firmware level threats.

UEFI Platform Security Flags (uefiplat.cfg)

The uefiplat.cfg is found in ARM firmware based on the Qualcomm implementation and it contains the SecurityFlag field which enables or disables several security features. The first bit of SecurityFlag is called SecBootEnableFlag and, as the name suggests, enables or disables Secure Boot. 

All ARM firmware in our dataset have this bit set, meaning that Secure Boot is enabled by default on these devices

Known PoCs against UEFI firmware

In this section we present some examples of proof-of-concept developed against UEFI firmware that clearly illustrate how the absence of mitigations can significantly simplify exploitation.

The first and most recent example is related to Bootkitty, a proof-of-concept bootkit for Linux. Despite its nature, Bootkitty is fully-functional in its UEFI capabilities, and exploits one of the vulnerabilities disclosed as part of LogoFAIL (BRLY-LOGOFAIL-2023-002). We covered the entire infection chain of Bootkitty in a previous blogpost

The high-level picture is that Bookitty stores a malformed logo on the ESP which gets parsed by a vulnerable DXE driver. The vulnerability results in an arbitrary write, which is used to patch the driver’s code in memory with a trampoline. When executed, this trampoline redirects the execution to a shellcode stored on the heap. 

Although an arbitrary write often leads to code execution, the absence of mitigations significantly simplified exploitation. 

  1. The lack of ASLR allowed predicting the driver’s base address and consequently where to apply the trampoline in the code section.
  2. The lack of NX allowed patching the driver’s code in memory and diverting the execution to a shellcode stored on the heap.

The second example is related to the PoC developed during our LogoFAIL research. The underlying bug exploited in this PoC is an integer overflow that results in a fully controllable heap overflow, allowing the attacker to control both the size and content. This overflow leads to code execution by overwriting a function pointer stored on the heap with an address under the attacker's control. 

The firmware used to develop the PoC didn’t have any mitigation enabled:

  1. Heap Guard was missing, allowing us to corrupt any memory allocated after the overflowing chunk without any limits.
  2. Control-Flow Integrity (CFI) was not enforced, enabling the hijacked function pointer to be redirected to any arbitrary memory location.
  3. No-eXecute (NX) was missing, and the PcdDxeNxMemoryProtectionPolicy was not properly configured, allowing us to store shellcode in an NVRAM variable and execute it, since NVRAM memory was marked as executable.
  4. Address Space Layout Randomization (ASLR) was not implemented, making it easy to predict both the heap layout and the location of our shellcode.
A slide from our BHEU 23 presentation “LogoFAIL: Security implications of image parsing during system boot”

The third example of known PoCs is related to System Management Mode, which is also affected by the absence of mitigations. As we discussed at Offensive Con and Black Hat, the lack of mitigations in SMM allows mounting ROP and JOP attacks. 

Finally, the lack of stack canaries allowed us to exploit stack-based buffer overflows and achieve code execution multiple times in the past. For example, when developing a working PoC for BRLY-2021-005 stack canaries were completely missing. On this device the stack was not executable, but we leveraged an improperly set NX policy to store the shellcode in the NVRAM area and redirect the execution flow there. 

In the case of BRLY-2022-033, canaries were also missing in the vulnerable function, but this time NX was correctly initialized, so we had to resort to ROP to gain code execution. These last two examples clearly show how mitigations often need to be used together, compounding their protection: relying on only one mitigation may not increase the difficulty of carrying out a successful exploit.

Conclusions

In this report, we took a deep dive into the mitigations implemented in the EDK2 reference implementation, exploring how they work, their strengths, and their weaknesses, as well as their adoption within the UEFI firmware ecosystem.

The results from our analysis presents an ecosystem that is very fragmented in the way mitigations are adopted, where some devices implement essential mitigations, while others are left completely without defenses. This fragmentation can also be seen in the firmware images themselves: mitigations are applied only to a few modules, but not based on their security relevance of modules but rather on which entity compiled them. These are concrete examples of the UEFI supply chain complexity, where firmware image is composition of multiple sources without a single, authoritative component that provides and enforces mitigations. 

A significant trend highlighted by this report is that vendors rarely tweak the default values provided in the reference implementation. This is evident in ARM firmware, the only platform where we consistently found stack canaries and properly configured NX, both of which are enabled by default in the reference implementation. In retrospect, ensuring robust mitigations’ implementations with secure default settings should have been a priority of the reference implementation. 

We applaud the recent addition of dynamic stack canaries for X86 targets, and we view this as a step in the right direction. However, based on our experience, it may take months, if not years, for this new implementation to permeate into the industry and to be adopted in UEFI firmware. For this reason, we urge the UEFI ecosystem to prioritize the adoption of this new implementation.    

Finally, we recognize that mitigations are often difficult to adopt as they often require trade offs between usability and security. However, in the UEFI firmware ecosystem, even basic mitigations with minimal side-effects are currently missing

We hope this research will motivate the industry to develop and adopt better mitigations for the UEFI firmware ecosystem, ensuring that billions of devices can be better protected against firmware-level threats.

The Binarly Transparency Platform identifies all discussed mitigations and provides verifiable, code-level evidence for in-depth analysis.

What's lurking in your firmware?