Security is a Cycle

How Intel Identified a Vulnerability in PCIe Integrity and Data Encryption, and Produced a Formally Verified Mitigation

 

Posted September 23, 2026

author-image

By

Authors:

Scott Constable, INT31
Arie Aharon, INT31
Hareesh Khattri, INT31

 

This article describes a protocol-level vulnerability in the PCIe IDE specification that was discovered by Intel researchers. Intel subsequently worked with the PCIe community to mitigate the vulnerability by defining a new protocol, which was finalized and published in PCIe Express Base version 7.1 in September 2026. Future PCIe devices will implement the new protocol, and existing devices can continue to be used with manageable risk. Please refer to the PCI-SIG’s CVE disclosure for the PCIe specification, and to INTEL-SA-01409 for Intel’s public security advisory and associated guidance for affected Intel products.

Security is never “done.” It doesn’t end when all the automated code scans complete with “0 bugs found.” A system architecture is not “secure” because it passed an expert review.

In early 2025, an Intel security engineer, Shalini Sharma, was studying the PCIe specification, an industry standard that governs the design of chip-to-chip interconnects for millions of commodity products: CPUs, GPUs, storage devices, network interface cards, and many more. Ms. Sharma was interested in a recent addition called Integrity and Data Encryption (IDE), which is intended to protect PCIe connections from man-in-the-middle attacks in datacenter environments. One particular page in the IDE chapter caused her to pause, step away from her computer, and grab a pencil and paper. She had been reading and re-reading a list of mathematical rules that underpin IDE, but the math didn’t seem to add up, like a puzzle whose one remaining piece doesn’t fit the one remaining gap. Several months later, Shalini Sharma’s discovery would become the first CVE ever to be issued for the PCIe standard. This vulnerability is now publicly known as Forbidden IDE Reordering, or FIR.

At Intel, we believe that security is a cycle—literally—in that it requires perpetual re-examination of everything that has already been examined. This blog tells the story of how Intel applied this philosophy to address FIR: how Intel found it, how we defined and formally verified a new protocol to fix it, and how we collaborated with the broader PCIe community to standardize the fix.

What Is IDE?

As its name implies, IDE provides encryption and integrity protection (courtesy of a Message Authentication Code or MAC) to shield PCIe traffic from snooping and tampering. It’s similar to the methods that protect the internet traffic sent between your laptop and your favorite web services. But it’s also different because PCIe has much stricter requirements for latency and bandwidth that have caused it to adopt optimizations.

For example, PCIe aims to minimize synchronization bottlenecks by dividing traffic into three basic categories of packets:
 

  • Non-Posted Requests ask the recipient to return data. For example, “Please respond with 64 bytes of data stored at address 0x80000000.”
  • Completions reply to Non-Posted Requests with data (“here are the 64 bytes you requested”) or an error status (“Your request could not be routed”).
  • Posted Requests send data to a destination. Most PCIe use cases don’t require Completions for Posted Requests and the sender doesn’t need to wait for a completion, which means that Posted Requests are generally the most efficient way to transfer data.


If you read the PCIe spec, you’ll notice that “not waiting” (for latency’s sake) is a common refrain. In fact, not only does a Posted Request not have to wait for a Completion, it also doesn’t have to wait for any other Non-Posted Request or Completions that were sent before it, as shown in Figure 1. This means that if an unrelated Completion is moving slowly through the PCIe traffic, the Posted Requests behind it can bypass it and reach their destination unimpeded.

Figure 1: PCIe Packets move left to right from the transmitter (Tx) to receiver (Rx). Purple triangles represent Posted Requests (write requests). These are "faster" (as indicated by motion marks) because they are allowed to pass Non-Posted Requests (red circles) and Completions (green squares).

But PCIe isn’t a total free-for-all, and some rules were imposed to bring sanity to the semantics. One such rule is that Non-Posted Requests and Completions cannot bypass Posted Requests. Without this rule, read operations could return stale data, and the following code might not always print “42” as one would expect:

*pcie_addr = 42;  // Send a Posted Request to write value 42 to a PCIe device’s memory
printf(“%d\n”, *pcie_addr);  // Send a Non-Posted Request, and wait for the Completion

The rules we have discussed so far apply to both PCIe and IDE, but they are more challenging to enforce within IDE’s threat model, which aims to address some categories of physical attacks against PCIe links. For example, a malicious PCIe switch could attempt to examine, modify, delete, or reorder PCIe traffic that passes through it. Encryption is sufficient to prevent attacks that aim to examine confidential data, and the MAC check prevents attacks that modify an IDE packet’s contents or header. But it is far from trivial to prevent attacks that reorder or delete IDE packets, especially given that PCIe legalizes some packet reordering to achieve its performance goals. The PCIe architects didn’t want to unnecessarily sacrifice performance at the cost of security, so they created some innovative schemes to win at both.

How IDE Enforces (Re-)Ordering

Before we dive into the innovative scheme in the PCIe spec, let’s first discuss a simpler enforcement scheme that certainly wouldn’t live up to IDE’s performance goals. Suppose that we introduce a new initialization vector (IV), a kind of counter that is maintained by both the transmitter (Tx) and receiver (Rx) of IDE packets. When an IDE session is started, the Tx and Rx both initialize their IV to 0. Each time an IDE packet is sent, the Tx includes its current IV in the MAC calculation and then increments the IV; symmetrically, the Rx uses its current IV in the MAC calculation when it receives an IDE packet and then increments its IV. This in-order enforcement scheme can detect when a malicious switch has reordered IDE packets, as in this example:

Suppose the Tx sends three IDE packets containing “Hello,” “World,” and “!” to the Rx:
 

  • The first packet contains the ciphertext of “Hello,” and a MAC that is calculated over the encrypted and plaintext contents of the rest of the packet with the Tx’s current IV, which is 0. Let’s express this packet as P(“Hello”, MAC(“Hello”, 0))
  • The second packet is P(“World”, MAC(“World”, 1))
  • The third is P(“!”, MAC(“!”, 2))

Now suppose that a malicious PCIe switch reorders the second and third packets before they reach the Rx. Let’s see what happens:
 

  • The Rx gets the first packet P(“Hello”, MAC(“Hello”, 0)) and uses its IV to compute the MAC for the encrypted data: MAC(“Hello”, 0). Since the MAC computed by the Rx matches the MAC in the packet, the check passes and the Rx decrypts and reads the plaintext “Hello.”
  • The Rx then gets the second packet, which is really the third packet that was sent: P(“!”, MAC(“!”, 2)). The Rx’s current IV is 1 (since it has received one packet so far), so it calculates MAC(“!”, 1). Since this does not match the MAC in the packet, the MAC check fails and the Rx terminates the IDE session.

The table below summarizes this scenario for the strict in-order enforcement scheme.

Although the in-order enforcement scheme prevents integrity violations, it is too strict for IDE’s performance objectives, which require Posted Requests to be able to bypass Non-Posted Requests and Completions. This dilemma led the PCIe architects toward a hybrid scheme that applies in-order enforcement within each category of traffic, while using a separate set of counters to detect ordering violations between traffic categories. Figure 2 illustrates this hybrid scheme:

Figure 2: IDE requires Non-Posted Requests and Completions to carry a number (for example, “1” or “2,” etc.) that indicates the number of Posted Requests that departed since the last Non-Posted Request or Completion, respectively.

Packets travel through three sub-streams—one per traffic category—from Tx to Rx. In-order enforcement prevents packets in the same sub-stream from passing each other. Posted Requests are allowed to pass Non-Posted Requests and Completions, but Non-Posted Requests and Completions must not pass Posted Requests.

IDE enforces these ordering constraints across sub-streams by requiring each Non-Posted Request and Completion to carry the number of Posted Requests that have departed since the last Non-Posted or Completion departed, respectively. For example:

  • In Figure 2, the first Completion that departed carries a “1” because one Posted Request departed before it
  • The second Completion also carries a “1” because one Posted Request departed since the prior Completion departed
  • The Non-Posted Request carries a “2” because two Posted Requests departed before it, and no Non-Posted Requests departed before it

In other words, when a Non-Posted Request or Completion arrives at the Rx with a number N, this number can be interpreted as, “you should have seen at least N Posted Requests that departed before me.” The words “at least” are critical. It’s obviously fine if exactly N Posted Requests arrived, and it’s also fine if more than N Posted Requests arrived, because Posted Requests are allowed to pass Non-Posted Requests and Completions. But if fewer than N Posted Requests have arrived, this can only mean that a Non-Posted Request or Completion must have passed a Posted Request, which isn’t allowed to happen.

Now let’s look at how IDE actually enforces this hybrid enforcement scheme.

IDE defines a pair of counters that are used to count the number of Posted Requests that have arrived since the last Non-Posted Request and Completion. Whenever a Non-Posted Request or Completion arrives, the Rx subtracts its number from the respective counter. If this subtraction underflows (meaning the result is negative), the Rx terminates the IDE session—this is how IDE detects prohibited packet reordering.

In theory, these counters suffice to immediately detect and prevent any malicious IDE packet reordering. But in practice, modern devices such as GPUs can send millions of Posted writes between two Non-Posted Requests or Completions. So, when, for example, the 10 millionth Posted Request has been sent since the last Completion, the next Completion will need to carry the number 10,000,000. Carrying such large numbers in IDE packets would require 4 or even 8 bytes per packet, which would significantly reduce IDE’s effective bandwidth, that is, the bandwidth that is carrying workload data.

The PCIe architects eventually arrived at a compromise: define a 1-byte field to hold the counter, and additionally define a mechanism called IDE Sync that resets the Tx’s counters to 0 and uses a dedicated “IDE Sync” Posted message to synchronize with the Rx whenever a counter is about to overflow.

It was this synchronization feature that made our inquisitive Intel engineer pause and think.

The Problem With IDE Sync

She started by writing down some example IDE packet sequences that involve an IDE Sync message. One observation grabbed her attention: whenever a Non-Posted Request or Completion carries the number 0, it can never trigger a subtraction underflow when it is received (because any non-negative number minus 0 remains a non-negative number). There are two cases where one of these IDE packets can contain 0:
 

  • Case 1: A Non-Posted Request is sent after a previous Non-Posted Request (or a Completion follows another Completion). In this case, the second Non-Posted Request cannot bypass any Posted Request that was sent earlier, because it cannot bypass the Non-Posted Request that was sent first (recall the IV that enforces strict ordering for Non-Posted Requests and Completions).
  • Case 2: A Non-Posted Request (or Completion) is sent after an IDE Sync. Unlike the first case, Shalini Sharma discovered that no mechanism in IDE can reliably prevent the packet sent after the IDE Sync from bypassing Posted Requests that were sent before the IDE Sync.

To understand why a forbidden bypass can occur in Case 2, let’s contemplate the scenario depicted in Figure 3. Suppose that the Tx has just sent hundreds of Posted Requests in a row. When one of the 1-byte counters is about to overflow, the Tx sends a special “S” Posted Request that resets the 1-byte counters. Now suppose that, by coincidence, the very next packet sent by the Tx is a Completion, which carries the number 0. Because that Completion carries 0 and has no other Completions in the lane in front of it, it can shoot across its lane, bypass all of the Posted Requests in the adjacent lane and never be caught by the Rx because it cannot trigger a subtraction underflow.

Figure 3: A scenario where a special “S” Posted Request (representing an IDE Sync message) is sent to prevent a counter from overflowing. When this packet departs, the counters are reset to 0, so if the next packet is a Completion it will carry the number 0, and can covertly bypass the Posted Requests without underflowing the Rx’s counters.

After this initial finding, we broadened our analysis and found even more examples that can violate IDE’s packet ordering requirements, including examples where the reordered packet can have a number higher than 0. While it might seem like the IDE Sync mechanism is fundamentally flawed, we made another observation that hinted at a workable solution.

The Solution: IDE Escort

Every violation that we studied seemed to require the first Non-Posted Request (or Completion) sent after an IDE Sync message to bypass that IDE Sync message. After a lot of trial and error, this observation eventually led to the solution that Intel has proposed to be included in an upcoming PCIe specification revision. We call this “IDE Escort.” The idea is intuitively simple. If our observation that the first Non-Posted Request or Completion after an IDE Sync must bypass the IDE Sync to allow any Non-Posted Requests or Completions to violate IDE ordering rules, then the vulnerability can be fully mitigated by preventing the first Non-Posted Request or Completion after an IDE Sync from violating the rules. Let’s see how this works in Figure 4.
 

Figure 4: A scenario where an “S” Posted Request (representing an IDE Sync message) is sent to prevent a counter from overflowing. IDE Escort requires the next Completion to carry a “−” and be escorted by a “+” Posted Request. This mechanism prevents the Completion from bypassing Posted Requests that departed before it.

 

Under the rules of IDE Escort, the first Non-Posted Request and Completion that follow an “S” Posted Request must be escorted by a special “+” Posted Request, and that Non-Posted Request or Completion must also carry a special “−” indication. The Rx must also maintain an additional pair of counters that are updated each time a “+/−” packet arrives:
 

  • Whenever a “+” Posted Request arrives, the Rx increments one of these new counters (there are two types of “+” Posted Requests: one that escorts Completions, and one that escorts Non-Posted Requests; for brevity, this example focuses on escorting Completions)
  • Whenever a “−” Non-Posted Request or Completion arrives, the Rx decrements the respective counter. An underflow (meaning the result is negative) indicates that a “−” Non-Posted Request or Completion has bypassed its escort.

In Figure 4, a Completion is sent after an “S” Posted Request (which represents an IDE Sync). IDE Escort requires that a “+” Posted Request must be sent immediately prior to the Completion, which is then promoted to a “−” Completion. If the Completion bypasses any of the Posted Requests (and therefore bypasses its escort), the Rx will decrement and underflow its counter, causing the IDE session to terminate.

Conclusion and How Intel Applied Formal Methods

After our initial findings, we found ourselves asking, “could this issue have been caught sooner by applying formal methods?” For decades, computer scientists have been using mathematical tools such as theorem provers and model checkers to maximize assurance for security-critical software, hardware, and protocols. At Intel, we have in-house experience using the Alloy model checker to verify security and correctness properties for our products. We immediately applied our expertise to build a formal model of the vulnerable IDE ordering enforcement protocol. When we checked an assertion that an ordering violation should always trigger an IDE error, Alloy almost immediately produced a counterexample that was similar to the ones we had scribbled with a pencil and paper.

Our next step was to try to envision a solution that would pass our assertions. In fact, IDE Escort was far from the first solution we concocted. We drafted and modeled a total of 8 candidate solutions that we believed would solve the problem. Alloy generated non-trivial counterexamples for 5 of the 8 solutions, which left us with 3 candidates that fully mitigate the vulnerability. We then collaborated with internal PCIe experts to determine which of the 3 would be most viable to standardize, and that left us with the IDE Escort solution.

If you’re interested in our modeling approach, we encourage you to check out the models and documentation that we have open-sourced.

Every month, our INT31 security research team publishes an article featuring our latest findings and insights. You can find all of our posts at our Blog Archive.

Acknowledgements

The authors would like to thank Arie Aharon, Scott Constable, Makaram Raghunandan, and Shalini Sharma for these internal findings.

They would also like to thank the Intel Product Security team for playing a pivotal role in addressing multiple third-party vulnerabilities (CVE-2025-9612, CVE-2025-9613, and CVE-2025-9614) discovered by Intel researchers in the PCI Express protocol’s Integrity and Data Encryption (IDE) feature. The team collaborated closely with key industry stakeholders—including Nvidia, AMD, and Arm—and guided the vulnerability management process. Intel drove the development of the Draft Engineering Change Notice (D-ECN) with PCI-SIG®, and worked in concert with mitigation partners, industry stakeholders, and the CERT Coordination Center to ensure a timely and responsible disclosure.

Share Your Feedback

We want to hear from you. Send comments, questions, and feedback to the INT31 team.

About the Author

Scott Constable is a security researcher in INT31. He received his Ph.D. in computer science from Syracuse University in 2018. Scott has contributed: Load Value Injection mitigations to LLVM/clang (2021); malicious single-step mitigations to the Intel SGX instruction set and Linux SGX SDK (2023); a transient execution attack taxonomy to the Common Weakness Enumeration (CWE) standard (2024); microarchitectural attack mitigations to the Linux kernel (2025); the IDE Escort feature to the PCIe standard (2026). Scott has also filed over three dozen patents that span cybersecurity, computer architecture, and generative AI.

Arie Aharon leads Intel TDX Connect and has over 15 years of experience in computer architecture and security. Arie’s past work included development of advanced security technologies, including AI-based malware investigation, static analysis, and formal methods.

Hareesh Khattri is a Principal Engineer and security researcher in Intel’s INT31 team. He has worked in hardware and platform security validation and research across multiple Intel technologies since 2006. His current focus is on Intel Xeon server designs and server platform security. Hareesh holds an M.S. in Electrical and Computer Engineering from North Dakota State University.