What changed, and why it matters
This update adds a safety check when the BitBox02 hardware wallet mounts a microSD card. A malicious or deliberately malformed FAT filesystem could trick the device's file-system library into placing user data inside attacker-controlled bookkeeping sectors, potentially leading to code execution or data corruption when the device later reads or writes files. The fix validates that the filesystem's internal layout is sane before using it, and leaves the third-party library code unchanged.
Treat this commit as a security fix. Ensure it is included in the next firmware release, verify that the new validation rejects the malformed BPB cases it targets, and consider adding unit tests with crafted FAT32 boot sectors to prevent regression.
Security signals we found
Fixes integer-wrap / geometry confusion in FAT mount logic
Adds explicit post-mount validation of filesystem metadata
Prevents data area from landing inside attacker-controlled FAT sectors
References a CVE identifier in the commit message
Leaves vendored FatFs untouched, indicating a boundary-hardening approach
Evidence from the diff
The patch introduces _mounted_geometry_valid() in src/sd.c, called immediately after f_mount() succeeds. It verifies that the mounted FATFS structure describes a FAT12/16/32 volume with 1–2 FATs and non-zero FAT size, and that the sector boundaries are ordered volbase ≤ fatbase ≤ database. Crucially, it checks that fatbase + fsize * n_fats does not exceed database, preventing an integer-wrap or mis-layout where the data area overlaps attacker-controlled FAT sectors. The commit states this addresses CVE-2026-6682 at the BitBox SD integration boundary without modifying vendored FatFs code.
Changed components
src/sd.cBitBox02 SD card / microSD integrationFAT filesystem mount pathInspect captured patch +21 / −0
diff --git a/src/sd.c b/src/sd.c
index 479a8c57..a31c6e58 100644
--- a/src/sd.c
+++ b/src/sd.c
@@ -29,6 +29,20 @@
static const char* ROOTDIR = "0:/bitbox02";
FATFS fs;
+static bool _mounted_geometry_valid(const FATFS* fatfs)
+{
+ if (fatfs->fs_type != FS_FAT12 && fatfs->fs_type != FS_FAT16 && fatfs->fs_type != FS_FAT32) {
+ return false;
+ }
+ if (fatfs->n_fats < 1 || fatfs->n_fats > 2 || fatfs->fsize == 0) {
+ return false;
+ }
+ if (fatfs->volbase > fatfs->fatbase || fatfs->fatbase > fatfs->database) {
+ return false;
+ }
+ return (QWORD)fatfs->fatbase + (QWORD)fatfs->fsize * fatfs->n_fats <= (QWORD)fatfs->database;
+}
+
/**
* Gets the full directory for an optionally given sub-directory.
* Also creates the sub-directory if it doesn't exist yet.
@@ -107,6 +121,13 @@ static bool _mount(void)
if (res != FR_OK) {
#ifndef TESTING
sd_mmc_pause_clock();
+#endif
+ return false;
+ }
+ if (!_mounted_geometry_valid(&fs)) {
+ f_unmount("");
+#ifndef TESTING
+ sd_mmc_pause_clock();
#endif
return false;
}
Why this scored 70/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.