USB Kill Switch for Qubes OS - Physical Security Enhancement

This guide explains how to set up a USB-based kill switch for Qubes OS that locks your screen immediately and shuts down your system shortly after a specific USB device is removed.
It’s similar to BusKill, but purpose-built for Qubes OS.
ONLY TESTED FOR XFCE ENVIRONMENT WITH THE XFCE SCREENSAVER

What it does:

  • Monitors a chosen USB device (flash drive, hardware token, etc.)
  • Locks screen immediately if device is disconnected
  • Shuts down after a set delay if screen remains locked
  • Resumes monitoring if you unlock before shutdown

Prerequisites

  • Qubes OS (tested on 4.2.4)
  • A USB device to act as your “key”
  • Basic terminal knowledge

Installation

1. Create Script Directory

mkdir -p ~/Scripts
cd ~/Scripts

2. Create the Scripts

SelectUSB.sh – Choose USB device to monitor

#!/bin/bash
ConfigDir="$HOME/Scripts"
mkdir -p "$ConfigDir"

ListDevices() {
    echo "===== Available USB Block Devices ====="
    Devices=()
    Types=()
    Index=1
    while IFS= read -r Line; do
        BackendDevice=$(echo "$Line" | awk '{print $1}')
        Description=$(echo "$Line" | cut -d' ' -f3-)
        Devices+=("$BackendDevice")
        Types+=("block")
        echo "$Index) $BackendDevice  -  $Description"
        ((Index++))
    done < <(qvm-block list 2>/dev/null | tail -n +2)

    echo
    echo "===== Available Raw USB Devices ====="
    while IFS= read -r Line; do
        BackendDevice=$(echo "$Line" | awk '{print $1}')
        Description=$(echo "$Line" | cut -d' ' -f3-)
        Devices+=("$BackendDevice")
        Types+=("usb")
        echo "$Index) $BackendDevice  -  $Description"
        ((Index++))
    done < <(qvm-usb list 2>/dev/null | tail -n +2)
}

ChooseDevice() {
    while true; do
        clear
        echo "USB Kill Switch - Device Selection"
        echo "=================================="
        ListDevices
        echo
        echo "Enter number to select device, 'r' to refresh, or 'q' to quit:"
        read -rp "> " Choice
        case "$Choice" in
            "r"|"R") continue ;;
            "q"|"Q") exit 0 ;;
            *)
                if [[ "$Choice" =~ ^[0-9]+$ ]] && (( Choice >= 1 && Choice <= ${#Devices[@]} )); then
                    SelectedDevice="${Devices[$((Choice-1))]}"
                    MonitorType="${Types[$((Choice-1))]}"
                    MonitorVM=$(echo "$SelectedDevice" | cut -d':' -f1)
                    MonitorDevice=$(echo "$SelectedDevice" | cut -d':' -f2)
                    echo
                    echo "Selected: $MonitorDevice from $MonitorVM (type: $MonitorType)"
                    echo "Press Enter to confirm..."
                    read
                    break
                else
                    echo "Invalid choice! Try again."
                    sleep 2
                fi
                ;;
        esac
    done
}

echo "Starting USB Kill Switch setup..."
ChooseDevice
echo "MonitorType=$MonitorType" > "$ConfigDir/USBDevice.conf"
echo "MonitorVM=$MonitorVM" >> "$ConfigDir/USBDevice.conf"
echo "MonitorDevice=$MonitorDevice" >> "$ConfigDir/USBDevice.conf"

echo "Configuration saved. Starting USB Kill Switch service..."
systemctl --user start monitor-drive-usbkill.service
echo "USB Kill Switch is now active!"
sleep 3

Tip:
If you want this selector to appear automatically after login (e.g., so you can choose your USB key every session), create a .desktop file in ~/.config/autostart:

[Desktop Entry]
Type=Application
Name=USB Kill Switch Setup
Exec=xfce4-terminal --command "/home/user/Scripts/SelectUSB.sh"
Terminal=true
X-GNOME-Autostart-enabled=true

Replace /home/user with your actual username.


USBKill.sh – Main monitoring daemon

#!/bin/bash
ConfigDir="$HOME/Scripts"
ConfigFile="$ConfigDir/USBDevice.conf"

if [[ ! -f "$ConfigFile" ]]; then
    echo "ERROR: No USB device configured."
    echo "Please run SelectUSB.sh first."
    exit 1
fi

source "$ConfigFile"

ShutdownTimeout=10
CheckInterval=0.5
DisconnectedTime=0

LogMessage() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | systemd-cat -t usbkill
}

IsDeviceConnected() {
    if [[ "$MonitorType" == "block" ]]; then
        qvm-block list "$MonitorVM" 2>/dev/null | grep -q "$MonitorDevice"
    else
        qvm-usb list "$MonitorVM" 2>/dev/null | grep -q "$MonitorDevice"
    fi
}

IsScreenLocked() {
    xscreensaver-command -time 2>/dev/null | grep -q "screen locked"
}

LockScreen() {
    if ! IsScreenLocked; then
        LogMessage "Locking screen due to USB disconnect"
        xflock4 &
    fi
}

LogMessage "USB Kill Switch started - Monitoring $MonitorType device $MonitorDevice on $MonitorVM"

while true; do
    if [[ $DisconnectedTime -eq 0 ]]; then
        if ! IsDeviceConnected; then
            DisconnectedTime=$(date +%s)
            LogMessage "USB device disconnected"
            LockScreen
        fi
    else
        CurrentTime=$(date +%s)
        ElapsedTime=$((CurrentTime - DisconnectedTime))

        if ! IsScreenLocked; then
            LogMessage "Screen unlocked — stopping service"
            systemctl --user stop monitor-drive-usb.service
            xfce4-terminal -x "$ConfigDir/SelectUSB.sh"
            exit 0
        fi

        if [[ $ElapsedTime -ge $ShutdownTimeout ]]; then
            LogMessage "Timeout reached — shutting down"
            shutdown now
            exit 0
        fi
    fi
    sleep $CheckInterval
done

3. Set Permissions

chmod +x ~/Scripts/*.sh

4. Create Systemd Service

File: ~/.config/systemd/user/monitor-drive-usbkill.service

[Unit]
Description=USB Kill Switch Monitor
After=graphical-session.target
Wants=graphical-session.target

[Service]
Type=simple
ExecStart=%h/Scripts/USBKill.sh
Restart=on-failure
RestartSec=10
Environment=DISPLAY=:0

[Install]
WantedBy=default.target

Usage

  1. Run:
~/Scripts/SelectUSB.sh
  1. Pick your USB key
  2. Service runs automatically and monitors the device

Customization

  • ShutdownTimeout=30 – seconds before shutdown
  • CheckInterval=0.5 – polling interval in seconds

Troubleshooting

  • Check logs:
journalctl --user -u monitor-drive-usbkill.service --no-pager
  • Make sure xscreensaver is running for screen lock

Uninstall

systemctl --user stop monitor-drive-usbkill.service
rm -rf ~/Scripts/
rm ~/.config/systemd/user/monitor-drive-usbkill.service
systemctl --user daemon-reload
2 Likes

Buskill has a Qubes specific guide

I never presume to speak for the Qubes team.
When I comment in the Forum I speak for myself.

I know BusKill’s Qubes guide. This is for people who don’t have BusKill. It works with any external device (USB, SD, external SSD) and is built specifically for Qubes OS.

1 Like