sprung is a small script with a single obsession: confirm a specific USB device is still present and still the same device, and if that identity check fails, slam the system into a forced reboot using a Magic SysRq trigger.

Not “log an alert.” Not “send a notification.” Not “ask politely.”
Just:if the talisman disappears, the ritual completes.

In classic terms, anti-forensics is anything that reduces, distorts, or denies the availability of forensic artifacts. sprung does that in a blunt, mechanical way: it ties the machine’s continued uptime to the presence of a specific hardware token, and forces an immediate reboot the moment the token is missing or its identity can’t be verified.


What sprung is actually doing (no incense, just Linux)

The core idea

Your OS can tell you a lot about a block device via udev. For a thumb drive attached as /dev/sdb, you can query:

udevadm info /dev/sdb

And you’ll see lines like:

sprung uses that output as its “identity oracle.” It watches for two broad failure modes:

  1. Device missing (unplugged, dead, controller freakout, etc.)
  2. Identity mismatch (something changed, you got swapped, or you’re reading the wrong device)

Either one means: panic button time.


How it checks whether the device exists

The script runs udevadm info <device> in a loop and inspects stderr.

When the device is gone, udevadm typically emits an error that contains "No such device" (on stderr), which is a convenient “corpse detection” string.

In the snippet:

device_info = subprocess.Popen(
    ['/usr/bin/udevadm', 'info', self.device],
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE
)

if "No such device" in device_info.stderr.readline().decode():
    found = False

So the moment /dev/sdb stops meaning anything, found=False, the loop can break, and the system is reset.


How it checks whether the device is the right device

Next, it reads stdout lines and searches for the serial:

for line in device_info.stdout.readlines():
    line = line.decode()

    device_serial_number = re.search('(?<=ID_USB_SERIAL_SHORT=).*', line)

    if device_serial_number is not None:
        if device_serial_number.group(0) == self.serial_number:
            found = True
            continue_loop = True
        else:
            found = False

So if the current device’s “short serial” doesn’t match the hardcoded expected serial, it treats that as a failure condition.


The “reboot” part: Magic SysRq as a guillotine switch 🪓

When sprung decides the device is missing or wrong, it calls:

def panic(self):
    cmd = 'echo b > /proc/sysrq-trigger'
    subprocess.check_output(cmd, shell=True)

That writes b into /proc/sysrq-trigger, which triggers an immediate reboot (no sync, no graceful shutdown). It’s intentionally brutal.

Why use SysRq?

Because it works even when the system is half-on-fire.

If your threat model includes:

But be honest: it’s a hard reset

SysRq b is not a polite reboot. It’s a table-flip reboot. Use it only if “the machine staying up” is a worse outcome than “the machine losing whatever it was doing.”

This can corrupt data. It can eat filesystems if you’re unlucky. That’s the point: it prioritizes state denial over state preservation.


What this is good for (and what it isn’t)

Good fits

Not a silver bullet


Downloads

GitHub: sprung

git clone https://github.com/ultros/sprung