Research

Microarchitectural Attacks on Trusted Execution Environments

A trusted execution environment is designed so that the code and data inside it stay protected even from privileged software. That stronger guarantee is why TEEs are used where the surrounding system cannot be trusted — managing cryptographic keys, handling biometric data on a phone, running computation over private data on infrastructure that belongs to somebody else.

The computation itself, however, runs on hardware built from caches, branch predictors, buffers, and a shared memory subsystem. I study how microarchitectural attacks on those components affect the security properties a TEE is meant to provide.

What interests me particularly is that the state a security monitor relies on in order to enforce isolation sits in the same hardware as the data it is protecting.

LLM Agents in Offensive Security

Large language models have grown markedly more capable, and offensive security is one of the areas where that shift matters most. What is still unclear is the shape of the capability: which parts of an attack an agent can now carry out on its own, and which remain out of reach.

I work on measuring that shape. Reverse engineering and binary exploitation are useful subjects because each is a long chain of dependent steps, so it is possible to observe not merely whether an agent succeeded but how far it got and where it stopped. Aggregate success rates hide exactly this: an agent that understands a program but cannot turn that understanding into a working exploit is a very different adversary from one that never understood it in the first place.

Knowing where agents break down is what makes the defensive question tractable. Protection aimed at a stage an agent already handles well returns little for the effort it costs; the same effort spent on a stage where agents reliably fail goes considerably further. I work on turning that into concrete guidance for software protection, so that resistance to LLM-driven attacks becomes something a system can be designed for rather than hoped for.

Security of RISC-V Privileged Software

RISC-V is an open instruction set architecture that has moved quickly from a research curiosity to production silicon. Its privileged-software ecosystem — the firmware and hypervisors running beneath the operating system — is correspondingly young, and everything layered above machine mode trusts that code unconditionally. A defect there does not weaken the guarantees above it; it voids them.

To find those defects efficiently I build fuzzing tooling for the layer. Hisame is a coverage-guided fuzzer for RISC-V SBI implementations such as OpenSBI and RustSBI: it instruments the emulator, restricts coverage to machine-mode execution so that only firmware counts, generates call sequences valid enough to get past argument checking, and detects memory errors inside the firmware itself. Ordinary fuzzers do not reach this code at all, because it runs before the infrastructure they depend on exists.

Automated Testing of Protocol Implementations

Shrinking a crashing input is well understood when the input is a file. It stops being understood when the target is stateful: the message you delete may be the one that put the server into the state where the bug exists at all, so a naive reduction quietly destroys the property it is supposed to preserve.

Minimization for protocol implementations therefore has to reason about state, not only bytes. Recovering an approximate state machine from the target’s own responses gives a criterion for which messages are load-bearing; only once those are pinned down does byte-level reduction mean anything. The payoff is unglamorous and practical: a smaller, faster test case for whoever has to sit down and diagnose the crash.