A USENIX ;login: article from July 2024 takes aim at a piece of conventional wisdom: that data-only attacks — exploits that never divert a program’s control flow, only corrupt the data it operates on — are too application-specific and too intricate to be a practical threat. The authors built a tool, Einstein, that generates them automatically, and got 944 confirmed exploits against nginx alone.

The setup is worth restating. Roughly 70% of the security bugs Microsoft, Google and Mozilla report are memory-safety bugs, so attackers usually start with a way to overwrite memory. Historically that meant overwriting a code pointer and hijacking control flow — the path that DEP, CFI and CPI were built to close.

What a data-only attack is

  • The program executes only its intended code, along every intended path. Nothing is hijacked.
  • What changes is the data the program acts on — in particular the arguments it passes to the kernel.
  • The canonical example: an attacker uses a memory write bug to change a web server’s cgi_bin_path from /usr/local/server/cgi-bin to /bin, then sends POST /sh with touch /tmp/attacker-was-here in the body.
  • The server concatenates its configured path with the request path, calls execve on /bin/sh, and politely executes the attacker’s command. The only thing the attacker corrupted was the argument to a syscall.

Why it was assumed to be impractical

  • Application-specific. Finding the security-critical variable supposedly requires deep knowledge of that program’s semantics — expensive, bespoke analysis for each target.
  • Complex. The literature assumed you had to solve heavyweight data-flow constraints, or build Turing-complete machines, to manufacture them.

The paper’s claim is that both assumptions are false, and that the tooling is the proof.

How Einstein does it

  • It is deliberately application-agnostic: instead of modelling HTTP or SQL, it targets the syscall interface, the one boundary every program shares.
  • Dynamic taint analysis tracks attacker-corruptible data through execution and flags where it reaches security-sensitive syscall arguments.
  • It looks for identity data flows — arguments copied verbatim from attacker-controlled data, the simplest and most useful case.
  • Each candidate is then confirmed the honest way: by actually running the exploit and checking that the predicted effect happens.

What it found

  • Test-suite workloads only reached 27–49% code coverage, which makes the numbers worse, not better.
  • attacker-tainted security-sensitive syscalls: httpd 1,834 (97% with an identity flow), nginx 1,623 (82%), redis 218 (84%), lighttpd 92 (98%), postgres 2,105 (27%).
  • Confirmed nginx exploits totalled 944: 1 code-execution, 17 write-what-where, 41 send-what-where, plus hundreds of partial write and send primitives.

The mitigation argument the paper lands on

  • Comprehensive defences — memory safety, full data-flow integrity — close the whole attack surface but are impractical to deploy.
  • Practical defences — memory error scanning, selective DFI, syscall filtering — deploy easily but leave gaps, and Einstein’s exploits walk straight through them.
  • For control-flow attacks, defences could be both. For data-only attacks, the trade-off is currently forced.
  • So the recommendation is for vendors to adopt the comprehensive defences, and for research to make them cheap enough to actually run.

The practical takeaway for anyone shipping C or C++ server software is that “we have CFI and we filtered syscalls” is not the reassurance it reads as. The mitigation layer everyone has been treating as sufficient is exactly the layer this tool is built to bypass, and the paper is explicit that the hard research problem is making the unserious-to-deploy defences serious.