• What happened: An attack called "Branch Target Reuse (BTR)" let code running with ordinary user privileges extract the Linux root account's password hash in an average of 3 minutes and 5 minutes on two Intel test setups.
  • Why it matters: By exploiting stale branch predictions that remain inside the CPU even after JIT code has been freed, the attack shows secrets can be read through a path that conventional isolation measures alone struggle to block.
  • What to watch next: How far the Linux and GraalVM fixes have reached products in actual use, plus how browser site isolation and the handling of branch predictions when JIT code is reused play out.

Researchers from VUSec at Vrije Universiteit Amsterdam in the Netherlands and Scuola Superiore Sant'Anna in Italy, among others, have disclosed "Branch Target Reuse (BTR)," a CPU attack that can read the password hash of the Linux root account in a matter of minutes.

On two Intel test setups, the attack bypassed the mitigations that were enabled on Ubuntu at the time. A local program running with ordinary user privileges obtained the hash in an average of 3 minutes and 5 minutes, respectively.

The key to the attack is a mismatch between a JIT compiler, which generates machine code at runtime, and stale branch predictions that linger inside the CPU. Even if the JIT-generated code itself is managed safely, the prediction information that remains in the CPU after that code is deleted is not necessarily safe. The research team's published materials

The paper, by Sander Wiebing, Yuhui Zhu and others, has passed peer review and been accepted at ACM CCS 2026.

What was obtained here was a password hash used for authentication. The experiment did not recover the plaintext password or seize root privileges themselves. Even so, it is significant that secret information that ordinary users should not be able to read leaked by using a legitimate JIT code-generation feature as a foothold.

AD

Branch predictions for deleted code remain in the CPU

A JIT compiler converts programs such as JavaScript into machine code as they run. To speed up frequently used operations, it generates code, then frees that code when it is no longer needed and reuses the freed memory region for other code.

JIT is used not only in web browsers but also in various language runtimes and in the Linux kernel.

Meanwhile, a CPU does not simply sit idle until a branch destination is settled.

For "indirect branches," where the jump target isn't known until execution, the CPU predicts the next destination from past execution history and runs instructions ahead of time. This prediction relies on structures such as the Branch Target Buffer (BTB).

If the prediction is wrong, the results computed ahead of time are discarded. However, the traces that data accessed during speculative execution leaves in places such as the CPU cache are not necessarily fully undone.

Spectre-style attacks observe these traces to infer secret information that should be inaccessible.

The problem BTR exploits is that branch predictions pointing to JIT code that has already been deleted remain inside the CPU.

First, the attacker moves execution from an indirect branch to the legitimate entry point of some JIT code, making the CPU remember that branch target.

The attacker then frees that JIT code and places different code in the same memory region.

An address that used to be the legitimate entry point of the code may now, in the new code, fall in the middle of an instruction or at a location holding mere data.

If the old prediction remains in the BTB, the CPU may still consider the earlier branch target valid and begin speculative execution from that location.

For example, a number embedded in machine code is normally treated as plain data. But if the byte sequence is read as instructions starting partway through, it can be interpreted as an entirely different instruction sequence.

The attacker tunes the program handed to the JIT so that, when execution starts from the location the old prediction points to, an instruction sequence that leads to reading secret information appears.

This works differently from a typical use-after-free.

It is not a case of a corrupted software pointer mistakenly accessing freed memory. What remembers the old address is the CPU's internal branch predictor.

That new code runs correctly as intended is a separate matter from whether it can be speculatively entered midway because of a past branch prediction. Attack principle and basic experiments in the paper (Sections 4 and 5)

Reading the root hash through unprivileged cBPF

The attack was demonstrated on Linux using the classic BPF (cBPF) JIT compiler.

cBPF is a small program execution environment used by features such as seccomp, which restricts system calls, and socket filters, which select network packets.

Even on systems that restrict the more capable eBPF for ordinary users, cBPF remains available to unprivileged programs.

The researchers installed a cBPF program as a seccomp filter and used the way the memory region holding JIT-generated machine code is freed and reused as part of the attack.

The test environment was Ubuntu 24.04 with Linux kernel 6.14.0-27, on Raptor Cove (Core i9-14900K) and Lion Cove (Core Ultra 9 285K) CPUs.

The attack runs from local, unprivileged code and does not require root privileges or a memory-corruption vulnerability in advance.

However, it was not an experiment in which the root password was stolen directly from outside over the internet.

The secrets needed for authentication are loaded into process memory when authentication takes place.

The target this time was the su command, which switches users. When su root is run, the root account's password hash is loaded into the process's memory.

The attack first traced the task list managed by the Linux kernel to find the su process.

It then read memory-management information such as page tables in turn, ultimately reaching the memory region where the root password hash is stored.

The "leak rate" figures in the paper need to be read separately.

The 5.7 KB/s and 5.4 KB/s in Table 2 of Section 6.1 are estimates calculated from the execution time and success rate of the attack's basic primitives.

The speed measured in the full attack, which locates where the secret is stored and actually reads the data, was an average of 8 bytes per second on both CPUs.

In a real attack, additional steps are needed, such as retraining the branch predictor for each candidate value and evicting data from the cache. The several-KB-per-second figure derived from the basic experiments therefore cannot be treated as the real-world attack speed.

Even so, obtaining the root hash took an average of 3 minutes on Raptor Cove and 5 minutes on Lion Cove.

This is because, rather than reading all of memory sequentially, the attack follows pointers in Linux's management structures to approach the small target it needs directly.

The paper's time breakdown shows that searching for the large shared memory pages the attack requires accounts for much of the total time.

The 3-minute and 5-minute figures are therefore not reproduced in every environment and will vary with factors such as installed memory and system load.

Obtaining a password hash can provide material for an offline attack, in which candidate passwords are hashed and compared against the stolen value.

Whether the actual password can be worked out from there depends on the password's strength and the hashing scheme used.

What this research demonstrated is the earlier stage: the leak of a hash value that is supposed to be protected.

AD

What was demonstrated differs across Linux, SpiderMonkey and GraalVM

The researchers examined three JIT environments: Linux cBPF, SpiderMonkey (the JavaScript engine used in Firefox) and Oracle's GraalVM.

However, the attack did not succeed to the same degree in all three.

How much of the CPU's stale branch prediction survives after JIT code is freed and the same address is reused varied with each JIT engine's memory management, compilation and garbage-collection behavior.

The table below organizes Sections 6.1–6.3 and 7 of the CCS 2026 paper by three questions: whether the mechanisms needed for the attack were confirmed, whether predictions survived code reuse, and whether obtaining secrets was ultimately demonstrated. It is not a table for comparing which is faster. The paper underlying the comparison

Target and test conditions What was confirmed Secret extraction demonstrated, and limits
Linux cBPF: Ubuntu 24.04, kernel 6.14.0-27, Intel Raptor Cove / Lion Cove Stale branch predictions remained after JIT code was reused and could be turned into a sensitive-data read Full attack to obtain the root password hash demonstrated. Averaged 8 bytes/s under default settings; hash obtained in 3 / 5 minutes on average
SpiderMonkey: Firefox 143 standalone JavaScript shell On Intel CPUs, an average of 6–7 stale branch predictions remained even after code was freed and reallocated Leak rate estimated at roughly 36 / 62 bytes/s. A full attack stealing secrets from the entire Firefox browser was not completed
GraalVM: x86-64 environment using GraalPy, two Intel CPUs An instruction sequence able to bypass memory-access bounds restrictions, and reuse of code addresses, were confirmed Predictions disappeared between freeing and reuse, so no actual secret leak was achieved

For SpiderMonkey, the researchers also examined not only Intel CPUs but also AMD Zen 4 and Arm Cortex-A76 and Cortex-X3.

In those environments, however, the branch predictions needed for the attack did not persist after the code was reused.

In GraalVM too, the JIT compilation and garbage-collection processes execute many branches, so the stale predictions the attacker wanted to use were erased by later processing.

The researchers say the constraints observed in GraalVM are not necessarily a fundamental defense. Still, an attack chain that does not currently work there cannot be treated as "demonstrated" in the way Linux's was.

It is necessary to distinguish between being able to reuse stale branch predictions in a CPU-level basic experiment and succeeding in obtaining secrets in a real OS or browser environment.

AMD CPUs were included in the basic experiments but were not used in the Linux root-hash experiment.

The paper gives as the reason that, in environments using AMD's AutoIBRS, the indirect branch predictions inside the Linux kernel targeted here are implemented in a way that cannot be used for the attack.

The Linux root-hash result on Intel therefore cannot simply be applied to AMD or Arm environments.

Constant blinding alone didn't stop it; instructions were embedded via another route

cBPF has a hardening measure called "constant blinding" that makes it harder for attackers to embed arbitrary machine code in numeric data.

Instead of leaving numbers embedded in JIT code as-is in the machine code, it replaces them with operations involving random values, making it hard for attackers to produce targeted byte sequences.

The researchers, however, devised a way to embed instruction sequences not in constants but in the offsets that indicate how far a branch instruction jumps.

Read from the normal position, they form a legitimate series of branch instructions; read from a position shifted by a few bytes, they are interpreted as a different instruction sequence usable for the attack.

With this second attack, even with constant blinding enabled, information was read at 10 bytes per second on both Intel CPUs, and the root hash was obtained within 5 minutes.

This shows that hiding constants alone does not remove every byte sequence produced by the JIT from an attacker's control. Experiment bypassing constant blinding (paper Section 7.2)

AD

IBT can't fully stop speculative execution under certain conditions

Intel has a mechanism called Indirect Branch Tracking (IBT) that checks whether an indirect branch has landed on a legitimate target.

In the research, on Raptor Cove, one instruction could be speculatively executed before the IBT check completed. On the newer Lion Cove, this timing gap was not observed.

That alone does not fully resolve the problem, however.

If an attacker can get the JIT to generate an instruction that IBT recognizes as a legitimate entry point, the landing point of the stale branch prediction itself can be made to look like a valid entry.

The paper evaluates the combination of IBT, which does not allow speculative execution before the check, and constant blinding as a strong defense. It does not, however, guarantee safety against every JIT implementation that may appear in the future.

Note that IBT was not enabled by default in the Ubuntu environment used for the experiments.

Linux discards stale branch predictions when code is reused

On the Linux side, a mechanism was introduced as a BTR countermeasure that discards old branch predictions when a JIT code memory region is reused.

According to the research team, on x86, when cBPF reuses a memory region in which cBPF or eBPF code previously ran, an Indirect Branch Prediction Barrier (IBPB) is executed on all CPU cores.

This is because clearing predictions on only one core might leave the earlier branch target on another core.

Two CVEs were assigned to the fix.

CVE-2026-64508 adds the groundwork for clearing prediction information when BPF JIT memory is reused.

CVE-2026-64507 is the fix that enables clearing via IBPB on x86.

The latter takes effect when Spectre-v2 mitigations are in use, and does not enable the additional clearing when the BPF caller is already protected against indirect branches by retpoline.

In other words, it is not a mechanism that clears branch predictions in the same way in every environment.

Oracle randomizes GraalVM's code placement

Oracle took a different approach from Linux.

In GraalVM, it introduced a change that randomizes where JIT code is placed, making it harder for an attacker to place targeted code again at an address that has been freed.

This fix was merged into GraalVM's development branch on August 19.

Whereas Linux responds by "erasing old branch predictions," GraalVM undermines the attack conditions by "making it harder to reuse the same address as before." The way BTR is addressed differs by software.

Site isolation is also an important defense in Firefox

In web browsers, not placing the attacker's code and secrets in the same process is also an important defense.

Mozilla's site isolation separates different websites into separate processes.

With speculative-execution attacks such as BTR, the attackable range is greatly limited unless the attack code and the target secret exist in the same address space.

The paper distinguishes between Firefox on desktop, where site isolation has been introduced, and mobile environments, where rollout is not yet complete. Mozilla also considered a countermeasure using IBPB, but is currently prioritizing completing and deploying site isolation.

It is therefore not appropriate to generalize this as "just opening a malicious web page lets an attacker steal secrets from another Firefox tab."

Although this research confirmed attack components against SpiderMonkey, it did not demonstrate a full secret-stealing attack using the entire Firefox browser.

Intel says it is "not a new hardware vulnerability"

On October 1, Intel published an official statement on BTR.

Intel says the reported behavior can be addressed by existing Spectre-v2-related guidance, including that for Branch History Injection (BHI) and Intra-mode Branch Target Injection (IMBTI).

It therefore does not classify BTR as a new Intel-specific hardware vulnerability and took the position that no new Intel-specific mitigation feature is needed.

At the same time, Intel is providing additional defenses for BPF JIT to Linux and advises users to update their OS and apply the existing Spectre-v2-related guidance.

Intel's assessment should be considered separately from the novelty of the research itself.

Previous Spectre-v2 countermeasures have focused on attacks that poison branch predictions from different privilege domains and similar contexts.

What BTR uses is the very branch target that the targeted branch legitimately used before.

Even when JIT code is deleted and different code is placed at the same address, the earlier branch target may remain inside the CPU.

What the researchers demonstrated is the question of whether a "branch target that was once correct" can still be treated as safe information after the code has been replaced.

Being able to defend with existing CPU features is not the same as existing software having already used those features where needed.

Fixes were underway before the research went public

Countermeasures did not begin after the research became public.

According to the paper, the researchers notified CPU vendors and Linux developers of the problem in April 2025, and shared additional results in May 2026 after completing the full attack.

The two Linux CVEs were published on July 25, and Oracle's GraalVM change was merged on August 19.

The research was made public on September 29, after coordination with vendors and fix work had progressed.

Linux's CVE information lists the first versions containing the fix as 6.1.183 in the 6.1 series, 6.6.145 in the 6.6 series, and 6.12.97 in the 6.12 series. 6.18.39, 7.1.4 and 7.2 are also listed.

However, Linux distributions may backport fixes into older kernels on their own.

Administrators therefore should not judge safety by the upstream Linux version number alone, but should check whether the kernel package of the distribution they actually use includes the fixes for CVE-2026-64507 and CVE-2026-64508.

For GraalVM too, a fix being merged into the development branch is a separate matter from that fix being reflected in the distribution you are using, so that should be checked separately.

JIT code must be protected beyond "the moment it is generated"

For those who develop JITs and sandboxes, the challenge BTR highlights is a longer-term one.

Intel's runtime guidance asks that, for code running in the same address space as secrets, speculative-execution countermeasures cover not only JIT or AOT compilers but also the runtime environment and host process. It also recommends prioritizing process isolation where possible.

What BTR shows is that it is not enough for a JIT to generate safe machine code.

One must verify what prediction information remains inside the CPU after that code is freed, and what meaning that prediction takes on for new code when the same address is reused for different code.

The safety of a JIT should be considered not by looking only at the generated instruction sequence, but as a whole process: the code is generated, executed and freed, and the same memory region is then handed to the next piece of code.