Contents
Introduction
barebox is an open-source bootloader for embedded Linux systems — the first code that runs when an ARM, MIPS, RISC-V, or x86 device powers on. This post documents four vulnerabilities I discovered across three of its subsystems:
| CVE | Subsystem | Bug Class | Impact |
|---|---|---|---|
| CVE-2026-34960 | DHCP client (net/dhcp.c) | Out-of-bounds read | Information leak / crash |
| CVE-2026-34961 | ext4 filesystem (fs/ext4/ext4_common.c) | Out-of-bounds read | Information leak / crash |
| CVE-2026-34962 | ext4 filesystem (fs/ext4/ext_barebox.c) | Infinite loop / memory exhaustion | Denial of service |
| CVE-2026-34963 | EFI PE loader (efi/loader/pe.c) | Integer overflow / heap overflow | Crash / potential code execution |
The four bugs share a single root cause: barebox uses fields from on-disk and on-wire formats as loop bounds, pointer strides, and arithmetic operands without validating them. A DHCP option scanner with no check that the packet contains its own terminator. An ext4 loop bounded by an unvalidated entry count read straight from disk. A directory iterator that never checks for zero-length entries. A PE section-size computation that overflows because both of its operands are 32-bit header fields. Each fix is one or two lines of code; each was absent in released builds.
Severity: none of these are remotely exploitable from the internet. The DHCP bug requires network adjacency during PXE boot. The ext4 and PE bugs require a crafted image on the device’s boot media — realistic in supply-chain attacks, compromised firmware updates, or environments where boot media integrity is not verified, but not “scan and exploit” targets.
What makes these bugs worth a detailed write-up is not the pattern — untrusted input used without validation is the most common bug class in C code. It is the context. A bootloader runs before the operating system starts. There is no ASLR (address space layout randomization — a defense that places code and data at unpredictable memory addresses, making it harder for an attacker to know where to write). There are no stack canaries (guard values placed between a function’s local variables and its return address, designed to detect if a buffer overflow has occurred). There is no heap hardening. There is no process isolation. All code runs in the same flat address space with full access to all hardware. A memory corruption bug that would crash one process in a modern OS can overwrite any byte in the bootloader’s memory — including the code that decides what to boot next.
The vulnerabilities were found using an AI agent following the structured analysis workflow described in my earlier post, and each was verified with AddressSanitizer-instrumented sandbox builds. Methodology is documented there; this post focuses on the bugs themselves.
Part 1: Background
What Is barebox?
barebox is an open-source bootloader maintained by Pengutronix, a German embedded Linux consultancy. A bootloader is the first software that runs when a device powers on — it initializes hardware, locates the operating system image, loads it into RAM, and transfers control to it. barebox is used on ARM, MIPS, RISC-V, and x86 hardware across industrial, automotive, and consumer embedded devices.
barebox was originally forked from U-Boot (the dominant open-source embedded bootloader) but diverged into a more Linux-kernel-like architecture: a virtual filesystem, a POSIX-like shell, and a driver model mirroring the Linux kernel’s. This architecture means barebox includes real filesystem drivers, network protocol parsers, and binary loaders — not minimal stubs but substantial C code that parses complex on-disk and on-wire formats. That complexity is where the vulnerabilities occur.
Sandbox Mode
barebox sandbox mode compiles the entire bootloader as a regular Linux process, using the host’s filesystem, network stack, and terminal in place of real hardware. It was designed for development and testing, but it is ideal for security research: compile with AddressSanitizer (ASAN — a compiler feature that inserts runtime checks around every memory access, detecting out-of-bounds reads and writes the moment they happen), feed crafted inputs, and observe exactly where memory safety violations occur. All four vulnerabilities were confirmed using ASAN-instrumented sandbox builds.
Why Bootloader Bugs Are Different
Most software today runs inside an operating system that limits the damage a single bug can cause. If a program reads past the end of a buffer, the OS detects the illegal memory access and terminates just that program. The rest of the system continues running.
A bootloader has none of these protections. It runs before the OS exists. Here is what that means concretely:
- No memory isolation. Every function, every driver, and every data structure shares one flat address space. A buffer overflow in the DHCP parser can overwrite the code that verifies the kernel image.
- No ASLR. Code and data are loaded at fixed, predictable addresses on every boot. An attacker who knows the bootloader version knows exactly where every function and every data structure is located in memory.
- No stack canaries, no heap hardening. The compiler-level defenses that modern operating systems enable by default are absent. A heap overflow writes directly into adjacent heap objects with no detection.
- Full hardware access. The bootloader can read and write any hardware register, any flash region, and any peripheral. A bug that gives an attacker control of execution in the bootloader gives them control of the entire device — including the ability to modify what operating system the device boots.
This is why even “low-severity” parser bugs in a bootloader deserve attention. A bug that would cause a simple crash in a userspace program can be the starting point for persistent device compromise in a bootloader, because there is no layer below it to contain the damage.
Part 2: DHCP Option Parsing — Out-of-Bounds Read (CVE-2026-34960)
When barebox performs a network boot (PXE boot — loading an OS image over the local network rather than from local storage), it acts as a DHCP client: it broadcasts a request, and a server on the local network responds with configuration (IP address, gateway, DNS servers). The response encodes this configuration as a list of options — tagged TLV (Type-Length-Value) fields, each with a 1-byte type, a 1-byte length, and then the data. A 0xff byte marks the end of the list. DHCP has no built-in authentication: any device on the local network can respond.
The Vulnerable Code
The bug is in net/dhcp.c, in the function dhcp_message_type(). This function scans the DHCP options field looking for option type 53 (the Message Type option, which identifies whether a DHCP packet is a Discover, Offer, Request, or Acknowledge). Here is the vulnerable code:
static int dhcp_message_type(unsigned char *popt)
{
if (net_read_uint32((uint32_t *)popt) != htonl(BOOTP_VENDOR_MAGIC))
return -1;
popt += 4;
while (*popt != 0xff) {
if (*popt == 53)
return *(popt + 2);
popt += *(popt + 1) + 2;
}
return -1;
}
Here is what each part does:
Line 1–2: The function receives popt, a pointer to the start of the DHCP options field within a received packet. It first checks for the BOOTP vendor magic (0x63825363) — a 4-byte signature that must appear at the start of the options field in every valid DHCP packet. htonl() converts the value to network byte order (most-significant byte first, which is the standard for network protocols). If the magic does not match, the function returns -1 (not a valid DHCP packet).
Line 3: popt += 4 advances the pointer past the 4-byte magic to the first option.
Line 4: while (*popt != 0xff) — the loop continues as long as the byte at the current position is not 0xff. In DHCP, 0xff is the end-of-options marker — a special sentinel value that signals “there are no more options after this point.” Every well-formed DHCP packet ends its options field with this byte.
Line 5–6: If the current option’s type byte equals 53, the function returns the value at *(popt + 2) — the first byte of the option’s data, which is the message type. Otherwise, popt += *(popt + 1) + 2 advances the pointer to the next option. The expression *(popt + 1) reads the length byte of the current option, and adding 2 accounts for the type and length bytes themselves. This is standard TLV (Type-Length-Value) parsing: skip forward by length + 2 to reach the next option’s type byte.
The Bug
There is no bounds check against the actual packet length. The loop’s only termination condition is finding a 0xff byte. If the options field does not contain a 0xff end marker — because the packet is truncated, malformed, or deliberately crafted — the loop will read past the end of the packet buffer into whatever memory happens to follow it.
Each iteration reads at least two bytes (*popt for the type and *(popt + 1) for the length), then advances by length + 2 bytes. With no upper bound on popt, every one of these reads can land in memory that does not belong to the packet. The loop continues until it either encounters a 0xff byte in adjacent memory (at which point it returns -1, having read an arbitrary amount of unrelated data), or accesses an unmapped page and crashes with a segmentation fault.
Figure 1 — The unbounded option scan. The loop checks only for a 0xff sentinel, not for the end of the buffer. Without the terminator, the pointer advances into unallocated memory (red zone) until it hits a random 0xff or faults.
Impact
This is an out-of-bounds read (CWE-125). The practical impact depends on what memory lies past the packet buffer: if adjacent memory contains sensitive data, the leaked bytes could influence subsequent parsing decisions; if the pointer reaches unmapped memory, the CPU raises a page fault and the bootloader crashes — halting the boot process entirely. On a device with no fallback boot path, this is a denial of service.
The attack requires network adjacency: the attacker must be on the same Layer 2 network segment (the local network — devices that communicate directly without going through a router). A rogue DHCP server that omits the 0xff end marker from its response triggers this bug automatically.
The Fix
The fix adds a bounds check that limits the loop to the actual length of the options field:
-while (*popt != 0xff) {
+while (popt + 2 < popt_end && *popt != 0xff) {
Where popt_end is one past the last valid byte of the options field, computed from the received packet length.
The exact bound matters more than it looks, so it is worth walking through. A single iteration reads three bytes relative to popt: the type at offset 0, the length at offset 1, and — when the type is 53 — the value at offset 2. A guard of popt < popt_end bounds only the first of those. It admits the case where popt is the last valid byte, and the read of the length at offset 1 then lands one byte past the end, with the option-53 value landing two bytes past. Requiring popt + 2 < popt_end is what puts all three reads inside the buffer.
One more thing this diff does not show. The function as written takes a bare pointer — dhcp_message_type(unsigned char *popt) — so popt_end does not exist in its scope at all. The real fix has to thread the received packet length in from the caller before this comparison can be written. The two lines above are the shape of the check, not a patch that applies on its own.
Demonstration
The DHCP parser had no check that the packet contained its own terminator. The next two vulnerabilities show the same pattern in a different domain: an ext4 filesystem driver that uses on-disk fields without checking whether they are self-consistent.
Part 3: ext4 Filesystem Vulnerabilities (CVE-2026-34961 and CVE-2026-34962)
ext4 is the standard Linux filesystem — the format used to organize files and directories on a disk partition. When barebox mounts an ext4 partition to load a kernel image or boot script from local storage, it parses on-disk structures: inodes (file metadata), extent trees (block-mapping indexes), and directory entries. These two vulnerabilities are both in this parsing code, and they share the same root cause as the DHCP bug: using input fields without validating them. A legitimate tool like mkfs.ext4 produces images where all fields are internally consistent. A crafted image can set those fields to values that exceed the actual buffer boundaries — and barebox uses them as loop bounds and pointer strides without checking.
What Is an Extent Tree?
ext4 uses extent trees to map logical file offsets (byte positions counted from the start of the file) to physical disk block numbers (the actual locations on the storage device where the data is written). An extent is a compact record that says “logical blocks N through N+L are stored starting at physical block P” — a range mapping rather than a per-block pointer, which is far more storage-efficient for contiguous files.
The extent tree starts in the inode (the on-disk metadata record for a file, containing its size, permissions, timestamps, and — critically — the root of its block mapping). The first 60 bytes of the inode’s block-mapping area hold an extent header followed by up to four extent entries (or index entries, for deeper trees). The extent header is a 12-byte structure containing:
| Field | Size | Meaning |
|---|---|---|
eh_magic | 2 bytes | Magic number (0xF30A) identifying this as an extent header |
eh_entries | 2 bytes | Number of valid entries following this header |
eh_max | 2 bytes | Maximum entries this node can hold |
eh_depth | 2 bytes | Tree depth (0 = leaf node containing extents) |
eh_generation | 4 bytes | Generation counter (unused in barebox) |
Each extent entry that follows is 12 bytes. In the inode’s inline block-mapping area (60 bytes), after the 12-byte header, there is room for exactly 4 extent entries (4 x 12 = 48 bytes). For larger files, the tree grows deeper: the root node holds index entries that point to additional blocks, each of which holds its own header and extent entries. But the key constraint is that the number of entries in any given node is limited by the size of the buffer holding that node.
CVE-2026-34961: Extent Tree Out-of-Bounds Read
The vulnerable code is in fs/ext4/ext4_common.c. When barebox resolves a file’s logical block number to a physical block number, it walks the extent tree. The iteration loop looks like this:
for (i = 0; i < le16_to_cpu(ext_block->eh_entries); i++) {
// process extent[i]
}
le16_to_cpu() converts the 2-byte eh_entries field from little-endian on-disk format to the CPU’s native byte order. The problem: eh_entries comes directly from the on-disk image and is used as the loop bound without any validation. A legitimate ext4 image will have eh_entries less than or equal to eh_max, and eh_max will not exceed the buffer’s capacity. But a crafted image can set eh_entries to any value up to 65,535.
If eh_entries is set to 100 but the buffer only holds 4 extent entries, the loop reads 96 entries past the end of the buffer. Each iteration reads 12 bytes (the size of an extent entry), so the out-of-bounds read covers up to 96 x 12 = 1,152 bytes of adjacent heap memory.
CVE-2026-34962: Directory Iteration Infinite Loop and Memory Exhaustion
The second ext4 vulnerability is in fs/ext4/ext_barebox.c, in the code that iterates directory entries. When barebox lists a directory’s contents or resolves a path component, it walks the directory’s data blocks parsing directory entries (on-disk records that associate filenames with inode numbers). Each directory entry has a direntlen field — a 2-byte value that specifies the total length of that entry, including padding. The iterator advances through the directory block by adding direntlen to the current file position:
while (fpos < dir->i_size) {
const struct ext2_dirent *dirent = buf + fpos;
// process the directory entry
fpos += le16_to_cpu(dirent->direntlen);
}
The bug: there is no check that direntlen is non-zero. If a directory entry on a crafted ext4 image has direntlen set to 0, the iterator adds 0 to fpos on every iteration. fpos never changes, the fpos < dir->i_size condition remains true forever, and the loop runs indefinitely.
In barebox’s sandbox mode, this manifests as memory exhaustion rather than a CPU-bound hang. Each iteration processes the same directory entry and triggers internal memory allocations through barebox’s VFS layer (the dir_emit() call that registers each directory entry allocates kernel objects via xzalloc() — a wrapper that allocates zero-initialized memory and aborts if the allocation fails). With direntlen = 0, the loop runs indefinitely without ever advancing, allocating memory on every iteration until barebox’s allocator reports:
EMERG: xfuncs: out of memory
EMERG: xfuncs: Unable to allocate 272 bytes
used: 16295792
free: 336
PANIC: out of memory
The used: 16295792 line shows that nearly 16 MB of memory was consumed by the infinite loop before the allocator failed — the repeated allocations filled the entire heap. On a real embedded device with limited RAM, this exhaustion would happen even faster.
Figure 2 — Two ext4 parsing flaws sharing the same root cause. Top: the extent tree loop uses eh_entries from the disk image without validating it and reads past the buffer. Bottom: a directory entry with direntlen=0 creates an infinite loop that exhausts all available memory.
Impact
Both vulnerabilities require the target to mount a crafted ext4 filesystem image — via a compromised firmware update, swapped boot media, or a rogue TFTP/NFS server on the local network. The extent tree OOB read (CVE-2026-34961) can leak adjacent heap contents or crash the bootloader. The directory infinite loop (CVE-2026-34962) is a reliable denial of service — the device will fail to boot, displaying the PANIC: out of memory message.
The Fixes
For CVE-2026-34961, the fix validates eh_entries against the buffer’s actual capacity before using it as a loop bound:
+if (le16_to_cpu(ext_block->eh_entries) > max_entries) {
+ /* eh_entries exceeds buffer capacity */
+ return 0;
+}
for (i = 0; i < le16_to_cpu(ext_block->eh_entries); i++) {
For CVE-2026-34962, the fix checks for zero-length directory entries and breaks the loop:
fpos += le16_to_cpu(dirent->direntlen);
+if (le16_to_cpu(dirent->direntlen) == 0)
+ break;
Both fixes follow the same pattern: validate the on-disk field before using it as a control flow parameter.
Demonstrations
Extent OOB Read (CVE-2026-34961):
Directory Infinite Loop (CVE-2026-34962):
The DHCP and ext4 bugs are variations of the same mistake — using an untrusted value as a loop parameter. The final vulnerability extends this pattern to arithmetic: a 32-bit integer overflow in the EFI PE loader.
Part 4: EFI PE Loader Integer Overflow (CVE-2026-34963)
The PE Format and EFI Loading
When barebox loads an EFI application (a UEFI-compatible executable), it must parse a PE (Portable Executable) file — the same binary format used for Windows .exe and .dll files, repurposed by the UEFI specification for firmware-level programs. A PE file contains headers (DOS, COFF, an optional header with the entry point and alignment parameters) followed by section headers — an array of structures describing where each section’s data is stored in the file and where it should be loaded in memory.
Each section header contains two fields critical to this vulnerability:
| Field | Size | Meaning |
|---|---|---|
VirtualAddress | 4 bytes | The offset from the image base where this section should be loaded in memory |
VirtualSize | 4 bytes | The size of the section in memory (may differ from the on-disk size due to padding or uninitialized data) |
What Is an Integer Overflow?
An integer overflow occurs when an arithmetic operation produces a result too large to fit in the variable’s data type, causing the value to wrap around. This is the same concept as the unsigned integer underflow described in my strongSwan post — but in the opposite direction. Where an underflow wraps a subtraction result from near-zero to near-maximum, an overflow wraps an addition result from near-maximum back to near-zero.
A 32-bit unsigned value holds 0 to 4,294,967,295 (0xFFFFFFFF). If you add two such values and the sum exceeds that maximum, the result wraps around. For example:
0xFFFFF000 + 0x2000 = 0x100001000 (33 bits)
truncated to 0x1000 in 32-bit arithmetic
The true sum is 0x100001000 (approximately 4.3 GB), which requires 33 bits to represent. But a 32-bit result can only hold the bottom 32 bits, so the high bit is silently discarded. The stored result is 0x00001000 (4 KB) — approximately one millionth of the intended value.
The Vulnerable Code
The vulnerable code is in efi/loader/pe.c, in the function efi_load_pe(). When loading a PE file, barebox needs to determine the total virtual image size — the amount of memory to allocate for the loaded binary. It does this by scanning all section headers and finding the maximum extent (the highest VirtualAddress + section_size):
for (i = num_sections - 1; i >= 0; i--) {
IMAGE_SECTION_HEADER *sec = §ions[i];
virt_size = max_t(unsigned long, virt_size,
sec->VirtualAddress + section_size(sec));
}
max_t is a macro that returns the larger of its two arguments, with a type cast to unsigned long. The expression sec->VirtualAddress + section_size(sec) computes the end address of the section — where it starts plus how big it is. The loop finds the maximum across all sections, which gives the total virtual image size.
The bug: the addition sec->VirtualAddress + section_size(sec) overflows.
It is worth being precise about which width causes that, because it is not the platform’s. Both operands are 32-bit fields read straight out of the PE section header. Under C’s usual arithmetic conversions the sum is therefore computed in 32 bits and wraps at 2³², on a 64-bit build exactly as much as on a 32-bit one. The max_t(unsigned long, ...) cast is applied to the result, and casting a value that has already wrapped does not bring the lost bit back. This is also why the upstream fix widens VirtualAddress to uint64_t before the addition rather than changing the type it is stored into.
A crafted PE file with a section at VirtualAddress = 0xFFFFF000 and VirtualSize = 0x2000 produces:
0xFFFFF000 + 0x2000 = 0x100001000 → truncated to 0x1000
The max_t comparison then receives 0x1000 (4 KB) instead of the true value 0x100001000 (~4 GB). If the .text section already established virt_size = 0x1200, the final virt_size remains 0x1200 (4.5 KB) because max(0x1200, 0x1000) = 0x1200.
barebox then allocates a buffer of only 0x1200 bytes:
efi_reloc = efi_alloc_aligned_pages(virt_size, ...);
Later, when copying sections into the allocated buffer:
memcpy(efi_reloc + sec->VirtualAddress, ...);
The write destination is efi_reloc + 0xFFFFF000 — an address approximately 4 GB past the start of a 4.5 KB buffer. This is a massive out-of-bounds write.
Pointer width does matter here, unlike in the arithmetic above, and the two cases differ. On a 64-bit build the offset is applied in full, the destination lands roughly 4 GB past the buffer in unmapped memory, the CPU raises a page fault, and the process dies with a segmentation fault. That is the crash the ASAN sandbox build reproduced. On a 32-bit build the pointer arithmetic wraps as well, and the same expression resolves to an address just below the buffer instead — so the write lands on whatever the allocator happened to place there, which is quieter and not what was measured here.
Figure 3 — The integer overflow chain. A crafted PE section with VirtualAddress near the 4 GB boundary causes the 32-bit size computation to wrap to a small value. The loader allocates a tiny buffer, then attempts to write at offset 0xFFFFF000 — approximately 4 GB past the start.
Impact
This is the most severe of the four bugs. An integer overflow leading to an undersized allocation followed by an out-of-bounds write is the classic pattern of an exploitable heap overflow (CWE-190).
In this demonstration, the write destination (efi_reloc + 0xFFFFF000) is so far past the allocation that it lands in unmapped memory and crashes immediately. With more careful tuning of VirtualAddress and VirtualSize, an attacker could produce a smaller overflow that lands in mapped heap memory, corrupting adjacent allocations or heap metadata. Whether that leads to code execution depends on the target’s memory layout, heap allocator, and available primitives — but the fundamental bug class (integer overflow to heap overflow) is well-established as exploitable.
The attack requires loading a crafted EFI PE binary — a compromised EFI application on the boot partition, a malicious firmware update, or a supply-chain attack that inserts a crafted binary into the boot process.
The Fix
The fix uses 64-bit arithmetic for the virtual size computation, preventing 32-bit truncation:
-virt_size = max_t(unsigned long, virt_size,
- sec->VirtualAddress + section_size(sec));
+uint64_t sec_end = (uint64_t)sec->VirtualAddress + section_size(sec);
+if (sec_end > MAX_VIRT_SIZE) {
+ /* section extends past allowable limit */
+ return NULL;
+}
+virt_size = max_t(unsigned long, virt_size, (unsigned long)sec_end);
By casting VirtualAddress to uint64_t before the addition, the sum 0xFFFFF000 + 0x2000 = 0x100001000 is computed correctly as a 64-bit value. The subsequent range check rejects any section that extends past a reasonable limit, and only then is the value downcast to unsigned long for the allocation.
Demonstration
Part 5: Key Takeaways
The Common Pattern
All four bugs follow the same pattern: a field from a parsed format (a network packet, a filesystem image, or a PE binary) is used as a loop bound, a pointer stride, or an arithmetic operand — without checking whether the value makes sense for the actual buffer. This pattern produces vulnerabilities in every parser codebase. In a bootloader, the consequences are worse than usual because no OS-level defense limits the damage (see “Why Bootloader Bugs Are Different” in Part 1).
Who Should Care
The attack surfaces are narrow: network adjacency during PXE boot, crafted media on an SD card or eMMC partition, or a compromised firmware update. These are not “scan and exploit” targets. But they are exactly the surfaces that matter for three groups:
- Embedded system engineers building products that boot from network or removable media. If your device performs PXE boot on an untrusted network, or accepts firmware updates without cryptographic signature verification, these bug classes apply directly to your threat model.
- Firmware update architects. If the update mechanism delivers a complete disk image or EFI binary to the bootloader, every parser in that path is a potential entry point. The ext4 and PE bugs in this post demonstrate that a single crafted field in the image can crash the bootloader or exhaust its memory.
- Security auditors reviewing bootloader code. The lesson is concrete: check every loop bound, every pointer stride, and every arithmetic operand that comes from a parsed format field. The fixes here were all one or two lines of code. The cost of adding them is negligible.
Sandbox Mode as a Verification Tool
The barebox sandbox mode is worth a note of its own. Compiling the bootloader as a regular Linux process, instrumenting it with ASAN, and feeding it crafted inputs from the command line reduced verification from “flash a board and observe serial output” to “run a command and read the stack trace.” For bootloader projects that do not offer a sandbox build target, vulnerability verification requires physical hardware and serial console access for every test iteration. That makes both development testing and security research slower by orders of magnitude.
Disclosure Timeline
All four vulnerabilities were reported to the barebox maintainers through their public mailing list and coordinated through VulnCheck for CVE assignment. The fixes have been merged into the barebox mainline repository.
References
- barebox project — Official site and documentation
- barebox source repository — Git repository maintained by Pengutronix
- VulnCheck Advisory — CVE-2026-34960 — DHCP option parsing OOB read
- VulnCheck Advisory — CVE-2026-34961 — ext4 extent parsing OOB read
- VulnCheck Advisory — CVE-2026-34962 — ext4 directory parsing infinite loop
- VulnCheck Advisory — CVE-2026-34963 — EFI PE loader memory safety
- AI-Assisted Vulnerability Analysis Methodology — Full methodology documentation
- CVE-2026-25075 — strongSwan Integer Underflow — Previous finding using the same workflow
- CVE-2026-29004 — BusyBox DHCPv6 Heap Overflow — Previous finding using the same workflow
Kazuma Matsumoto. “Four Vulnerabilities in barebox: From DHCP Parsing to EFI PE Loading”. 637th Research Lab, 2026-07-12. https://y637f9qq2x.com/posts/barebox-sandbox-vulns/
