How Fuzzing Found a DoS Vulnerability in the ActivityPub Server snac2

Translated by a model; the original is in Russian.

· Security
Inspired by debates about the future of vulnerability research, a novice researcher took the popular minimalist server snac2 and, within minutes of fuzzing, discovered an unauthenticated remote denial of service.

cover.svg

The author of the Nullenvk blog describes how, inspired by discussions about whether vulnerability hunting will remain a human endeavor in the age of advanced LLMs, he decided to test a simple question: how hard is it for an inexperienced researcher in 2026 to find at least one medium-severity bug in a non-trivial open-source project. His only experience was in binary exploitation for CTFs; he had hardly ever broken real software before.

Choosing a Target

The author found no interest in breaking trinkets used by a handful of enthusiasts, so he took snac2 — a minimalist ActivityPub server that powers many small and several large Fediverse instances. The project is written in C (with all the classic memory-handling risks), contains its own parsers, and yet uses real defensive measures — optional Landlock on Linux and pledge/unveil on OpenBSD.

Attack Surface

The author confined himself to code reachable by a remote, unauthenticated attacker. It turned out that a POST request with the header Content-Type: application/activity+json kicks off JSON parsing even before the endpoint is checked. That made for a convenient target.

Fuzzing

Instead of reading the code by hand, he set the AFL++ fuzzer loose on the JSON-parsing function, writing the simplest possible harness that reads a file and hands it to the parser. The first crashes appeared within minutes. The suspicious input was reduced to a sequence containing \u0000, after which the local server reliably crashed on a small request.

The Root of the Bug

The cause was found by his friend dzwdz while the author was asleep. The parser has a check that replaces dangerous control characters with visual representations. But the condition strchr("\r\n\t", cp), given a null character, concludes that the byte 0x00 is part of the string — after all, zero is its terminator. As a result, the null byte ends up inside the string. Further down, the buffer size is computed via strlen, which stops at the null byte, so the buffer is endlessly reallocated to the same size while new characters are written past its bounds — a classic heap overflow.

Impact and Disclosure Ethics

A tiny POST request instantly takes down any snac2 server — an unauthenticated remote denial of service. Worse still, a malicious instance could craft a legitimate ActivityPub object that would propagate across the network and bring down other nodes. The author has not yet managed to turn the overflow into an arbitrary write and full RCE: ASLR and pointer protection get in the way. The vulnerability has already been fixed (a link to the commit is provided in the original), a CVE request has been filed with MITRE, and this write-up came out a couple of weeks after the release of the patched version.


Source: Lobsters

Comments

Sign in, to comment.

  • No comments yet.