Researcher finds 14 Prusa MK4S firmware flaws, one giving RCE

A freelance security researcher who works in Platform Engineering, SRE and databases, and does security research as a hobby, spent a full week in August attacking his own Prusa MK4S. The printer was running the signed upstream firmware 6.5.7 (build 6.5.7+12836). The result was 14 findings, roughly 23 individual defects, and a chain that ends with the printer's main controller running code the author sent over the network. The disclosure was coordinated with Prusa and published at the same time as the official security advisories. Prusa has fixed every finding in Buddy firmware >7.0.0, and owners should update. The author has requested CVE assignments for all findings, which he expects soon.
The author says firmware and hardware were new to him; he had never written Cortex-M assembly. His setup was basic: the printer, the signed image, "Opus 4.8 and a fuzzer". He started with G-code parsing and Prusa Connect, on the theory that bugs cluster where user input comes in, and that is where the most serious ones turned up. More came from the USB and FAT path, the transfer-recovery code, and smaller defects on the MMU and EEPROM side.
The method had four parts: compiling the firmware's own parser code for the host under AddressSanitizer, so crashes sit in Prusa's shipped code; building a small Cortex-M emulator that runs the real signed image, to prove the control flow before touching the printer; running millions of mutated iterations against the G-code path and millions of mutated HTTP requests against PrusaLink and Connect; and extensive reverse engineering plus several parallel source audits, each of which had to record the files it did not open. The hardest part was the control-flow primitive. Of a pile of candidate dispatch sites, exactly one worked for the RCE.
The author sent Prusa two disclosure packages, along with the whole worktree he had built, methods and scripts included, so the developers could repeat the process. The first package held four findings. Three are confirmed on the physical printer, from crash dumps the printer wrote itself and from a complete takeover of the controller. The fourth, an off-by-one on the MMU side, is source-verified only. The second package held the other ten, confirmed under AddressSanitizer or by source review only. The split was deliberate: a bug seen crashing real hardware and a bug reasoned out from the source tree are not at the same confidence level, and mixing them might have led Prusa to over-trust the weak ones or under-trust the strong ones. Every finding came with a write-up and, where applicable, PoC code.
The most serious bug is in Prusa Connect, the cloud or self-hosted service a printer can talk to for management and dispatching prints. When Connect sends a SEND_FILE_INFO command, the controller's handler copies the command's path into a shared 512-byte buffer, bounded by the buffer size. But the filename is stored in the same buffer right after the path, found by walking off the end of the path string, and that layout is only safe if the path is at most 104 bytes. The only enforcement is an assert(), which release builds compile out under NDEBUG. A 463-byte path therefore pushes the filename write past the buffer and onto the pointer through which Connect's command planner dispatches printer calls. The next virtual call walks that pointer and goes wherever the attacker pointed it. The file need not exist on the printer.
The payload is self-contained: the command sits in the network receive pool, so the path's own bytes carry the fake object, the fake dispatch table and the code, with no heap spray and no second channel. The firmware has no stack canary and no _FORTIFY_SOURCE, which turned the bounds slip into program-counter control rather than a simple crash. The finding scores a preliminary 8.1 High. It has a precondition: the attacker must be the Connect endpoint the printer talks to, or be able to MITM it. That includes a compromised Connect backend, and on a LAN, where ARP spoofing is an option, the author calls it a realistic position. He tested with TLS off in the printer's local config, so a MITM would still have to downgrade TLS for a printer using the official cloud-based Prusa Connect. Confirmation came from the printer's own crash dump, written to USB on a crash: two marker values in registers that only the author's shellcode writes, a program counter inside his own bytes, and a return address just past the dispatch. He recorded a PoC for Prusa and says he will release the full PoC code, for each bug where applicable, most probably in December, to give people time to patch, possibly around Congress / 40C3.
The rest of the first package covers three more findings. A crafted USB filename overflows a stack path buffer in get_SFN_path. The firmware rewrites a path's last component in place with the FAT short name, assuming a short name is never longer than the long name, and the guard is another assert() that release builds drop. The assumption fails on hand-written media: Prusa maps the FAT codepage as an identity map, so each high byte becomes two bytes of UTF-8, lifting the ceiling for the whole name to 23. It scores 6.4 Medium for the program-counter control it gives. The hijack shown does not run the author's own code, and he calls that limit structural: the overflow bytes must spell a FAT 8.3 short name, which cannot name a RAM address or a useful gadget. It needs physical USB access, and that alphabet plus the stick having to be present at power-on is why the score rates attack complexity as high.
Then an off-by-one in the MMU progress converter: the bound is <= where it should be <, so one index past a 29-entry table is accepted, read as a pointer and walked as a string. It is source-verified only, needs a faulty or malicious unit on the MMU bus, and the author rates it 3.5 Low. It is also the finding he first got wrong: he thought genuine Prusa hardware sends the triggering code during the MMU self-test, but tracing the call order showed the self-test runs before the serial receive path is enabled. The report went to Prusa already corrected. Its advisory shows 6.4 because the same write-up also covers two EEPROM defects, scored 6.4 and 3.1.
Finally, the encrypted-G-code (E2EE) identity block sizes a buffer and a read from the same attacker-controlled header field, using two subtractions that differ by 11. For a narrow band of values the allocation comes out at 0 to 10 bytes while the read length underflows to roughly 4 GB, then clips to the file's remaining bytes, so the attacker picks both the length and the content of the overflow. The apparent guard never fires because the function that should reject a short header returns zero instead of an error. It runs when the printer scans a print preview from a USB stick, with no signature check and no CRC, and without starting a print. It scores 6.1 Medium. The author confirmed it five times on hardware: it gives reliable denial of service but not reliable code execution, because the heap put the overflow in four different places across those five runs.
The second package's ten findings are each described in their own write-ups, linked from the original post, and are not detailed here.
Key facts
- A freelance researcher spent a week in August attacking his own Prusa MK4S (firmware 6.5.7) and reported 14 findings, roughly 23 individual defects, to Prusa.
- The worst chain goes through Prusa Connect: an oversized SEND_FILE_INFO path (463 bytes against an assumed 104-byte cap, enforced only by an assert() compiled out of release builds) overflows a shared 512-byte buffer and hijacks the program counter. Preliminary score 8.1 High.
- Other first-package findings: a USB filename overflow in get_SFN_path (6.4 Medium, physical access), an MMU off-by-one (3.5 Low, source-verified only) and an encrypted-G-code header heap overflow (6.1 Medium, reliable denial of service).
- The disclosure was coordinated with Prusa and published alongside its advisories; every finding is fixed in Buddy firmware >7.0.0, and CVEs have been requested.
- The author plans to publish full PoC code most probably in December, to give owners time to patch.
Why it matters
A consumer 3D printer is a networked computer that often sits on a home or office LAN and takes files from USB sticks. This write-up shows a path from a single network command to code running on the printer's main controller, in firmware with no stack canary and no _FORTIFY_SOURCE. The root causes are ordinary: a layout that is safe only under a 104-byte cap, and checks written as assert() calls that release builds compile out. The author also notes a researcher with no prior Cortex-M experience got this far in a week using Opus 4.8, a fuzzer, an emulator and AddressSanitizer, and says an agent could derive its own PoC from his write-up.
Who it affects
Owners of Prusa printers on the affected list at the end of the original post, which covers the MK4S the author tested. That list is not reproduced here. The 8.1 High chain matters most to people who connect their printer to Prusa Connect, especially on a LAN where ARP spoofing is possible, or to a self-hosted Connect endpoint. The USB findings matter to anyone who plugs in sticks they did not prepare themselves, though the filename bug also requires the stick to be present at power-on. Prusa's developers are affected too: the author handed over his full worktree, methods and scripts.
How to use it
If your printer is on the vendor's affected list, update to Buddy firmware >7.0.0, which fixes every finding in the post. Until then, the author's own analysis points to the exposure: the Connect chain needs an attacker who is, or sits in the path of, the Connect endpoint, and the USB filename bug needs physical access. The advisories hold the full write-ups. The author has requested CVE assignments, and he says he will release the PoC code most probably in December.
How solid is it
The most serious finding is backed by hardware evidence: the printer's own crash dump held two marker values only the author's shellcode writes, a program counter inside his own bytes and a return address just past the dispatch. The disclosure was coordinated with Prusa and released with its official advisories, and Prusa has fixed every finding. Confidence varies by finding, and the author says so: three of the first package's four findings are confirmed on hardware, the MMU off-by-one is source-verified only, and the ten in the second package are confirmed under AddressSanitizer or by source review. The E2EE bug was reproduced five times on hardware. The 8.1 score is described as preliminary, and the CVE identifiers are requested but not yet assigned. This retelling relies on the author's own account of the work.
Risks and caveats
The RCE has a precondition: the attacker must be the Connect endpoint or able to MITM it. The author tested with TLS off in the local config, so against the official cloud Prusa Connect a MITM would still have to downgrade TLS. The USB filename bug gives program-counter control but not the author's own code execution, and needs physical access. The MMU off-by-one needs a faulty or malicious unit on the MMU bus. The E2EE overflow yields reliable denial of service but not reliable code execution, since the overflow landed in four different places across five runs. The author initially misjudged the MMU finding and corrected it before reporting. Public PoC code is planned for December, so unpatched printers become easier to attack after that.
“14 findings, roughly 23 individual defects, and a chain that ends with the printer's main controller running code I sent it over the network.”
— The researcher, in his blog post on dixken.de