Low-level & embedded security research
Memory-corruption, protocol and firmware research against code that ships as a binary — network stacks, packet processing, and everywhere source review and package scanning stop.
Where source-level assurance runs out
Most security tooling assumes source. Package scanners read manifests. SAST reads repositories. Dependency alerts describe what the build declared.
Embedded and low-level software breaks all of those assumptions. The thing that ships is a binary: statically linked, frequently stripped, often carrying vendored code nobody tracked, running on a platform where the sanitizers you would want are unavailable and the fuzzers you have cannot reach past the parsing layer.
That is the surface we work on. It pairs directly with binary SBOM verification — that service answers what is in your artifact, this one answers what an attacker can do with it.
Your coverage is high and your crash count is zero
Both facts are compatible with a live bug, and they look identical on a dashboard to the state where none remain.
Harnesses reach the parser and not the state machine behind it. Differential fuzzing catches divergence but is structurally blind to out-of-bounds reads and uninitialized memory, because both implementations happily agree on a wrong answer. Sanitizers get disabled on exactly the platform where the interesting code runs — which on embedded targets is most of them. Structure-aware mutators stop generating the input shape that reaches the bug at all.
What you get
- Findings with working proofs of concept. No theoretical bugs, no "could potentially." If we call something exploitable, there is a PoC and you can run it.
- Root-cause analysis, not a crash bucket — the bug class, why it is reachable, and the correct fix at the design level rather than at the crash site.
- Exploitability assessed honestly, including what bounds it. Mitigations that hold, allocator behaviour that refuses to cooperate, the reason a primitive does not chain. On embedded targets that analysis frequently is the finding, because the mitigations you would rely on elsewhere are often absent.
- A coverage ledger — every surface and bug class considered, with a verdict and evidence per cell, including what came back clean and how we know.
- Harness gap analysis: where your existing fuzzing structurally cannot reach, and what to build to close it. Usually the most durable thing you keep after we leave.
- Fix verification on a follow-up pass, if you want it.
How we work
Attack surface first, ranked by reachability. Every entry point an untrusted party can touch — network, bus, radio, update channel, removable media, debug interface — ordered by what sits behind it rather than by what is interesting to read.
Reachability before code. Where privileged operations are out of scope, who can reach this decides whether a bug matters, and it is far cheaper to answer than to read the subsystem first.
Manual review aimed by novelty and churn. Recently-changed code that post-dates the last review is where bugs live. Reading in file order spends a week where everyone has already looked.
Custom harnesses for what your fuzzing cannot reach, including reachability canaries that prove the harness is exercising the target. A green campaign against a silently unreachable target is the most expensive kind of nothing — and on cross-compiled embedded targets it is the normal failure.
Static analysis as leads, never findings. Stock rule packs return zero on codebases with known live bugs. A zero from an untuned pack is a statement about the pack, not the code.
Full exploitation only where it changes the answer. If you need to know whether something is a real threat or an annoyance, we build the chain. If severity is already clear, the budget goes to the next surface.
Network stacks, protocols and packet processing
This is the sharpest version of the surface above, and it gets its own section because the economics are different.
A protocol parser bug is pre-authentication and remotely reachable. There is no cheaper position for an attacker to occupy — no credential, no user interaction, often no session. On a network-facing device the parser is the perimeter.
The stack is almost never yours. TCP/IP implementations, TLS libraries, ASN.1 and TLV decoders, protocol state machines — overwhelmingly third-party, frequently forked years ago, and usually invisible to a build-time manifest. This is where this service and binary SBOM verification meet: one establishes which stack you actually shipped and how far behind it is, the other establishes what an attacker does with it.
Protocol fuzzing is where harnesses most reliably fail silently. Checksums, handshakes, sequence numbers, length prefixes and multi-packet state mean a naive harness never gets past the first packet. Coverage looks respectable because the parsing entry point is well exercised; the state machine behind it is untouched. A campaign can run for months in that condition and report nothing, because there is nothing to report about code it never reached.
What we look for:
- Length and bounds handling across parse, reassembly and re-serialization — the classic fragmentation and TLV shapes, and the arithmetic that precedes the allocation
- State-machine flaws: messages accepted out of order, in the wrong state, or after teardown; transitions reachable without the authentication step that was supposed to precede them
- Reassembly and fragmentation logic, including overlapping and duplicate fragments
- Parser differentials between implementations — where two peers disagree about what a packet means, which is both a bug class in itself and a strong oracle for finding others
- Dataplane and offload paths: kernel networking, eBPF/XDP, DPDK-style userspace processing, and SmartNIC/DPU offload, where the usual mitigations are thinnest and the code runs on every packet
Harness construction is usually the deliverable that lasts here — a stateful, checksum-aware fuzzer that actually reaches the state machine, with reachability canaries proving it does.
Target classes
Memory corruption, use-after-free, type confusion, integer issues and the allocations downstream of them, privilege escalation, secure-boot and update-path flaws, IPC and privilege-boundary bugs, parser and deserialization bugs, and logic flaws in security-critical state machines.
Platforms
Firmware and RTOS, Linux and kernel modules, bare-metal ARM/RISC-V, network stacks and packet processing paths, device update mechanisms, protocol implementations, and native code reachable from managed runtimes on desktop and mobile.
Engagement shapes
| Shape | Fits | Typical duration |
|---|---|---|
| Targeted assessment | One subsystem or attack surface | 2–4 weeks |
| Product assessment | Full attack surface of a device or product | 4–8 weeks |
| Harness engagement | We build the fuzzing infrastructure and hand it over | 2–4 weeks |
| Retained research | Continuous, across releases, N days/month | ongoing |
Scoped per engagement. For a team that already fuzzes, the harness engagement is usually the best first project — the deliverable keeps working after we leave.
Questions we get asked
What if you find nothing? Then we say so, and hand you the ledger showing where we looked and what we tried. That is a real result — it is what a ship decision needs. We would rather deliver an honest empty engagement than pad a report, and we will say that before you sign.
We already run a bug bounty. Why pay for this? Bounties are excellent at breadth and poor at depth: they pay per finding, so researchers stop at the first reportable bug and rarely invest in a hard surface. They also cannot tell you where nobody looked. Embedded targets in particular get very little bounty attention, because acquiring and instrumenting the hardware is a barrier most participants will not cross.
We don't have source for part of it. That is normal, and often the interesting part. We work from the binary.
Do you need physical hardware? Sometimes. Emulation covers a lot, and we will tell you when it does not — a finding that only reproduces on real silicon should be demonstrated on real silicon.
Start a conversation · hello@rev3rse.dev