hackprinceton2026

Backflow

Every command to a water plant, checked against physics before it runs.

Live demo: backflow.design (plays a recording of the real system on a loop)


Inspiration

On 30 July 2026 the FBI and EPA put out a warning: attackers were changing settings on internet-facing pump controllers at water systems in at least seven US states.

The targets weren’t big city utilities with security teams. They were small towns, where one operator looks after the whole system and is on call at 3 a.m. The controller that runs the chlorine doser sits on the same network the contractor uses for remote access. If someone gets in and sets the doser to 100 %, nothing stops it. The controller does what it’s told.

Firewalls don’t help here because the attack looks completely normal. It’s a valid Modbus write, from an address that’s allowed to write, to a register that’s meant to be written. The only way to see it’s wrong is to ask what the command would do to the water.

So we built a box that asks exactly that.


What It Does

Backflow is a safety gateway that sits between remote access and the pump controller. Every command goes through it, and every command gets run forward through a physics model of the plant before it’s allowed to reach the controller.

COMMAND ➔ PARSE ➔ POLICY + PHYSICS ➔ ALLOW or HOLD ➔ AGENT INVESTIGATES ➔ OPERATOR DECIDES ➔ REPORT

How We Built It

Tech Stack

Architecture

 remote access ──► GATEWAY ──(allowed only)──► ESP32 STATION ◄── PLANT TWIN
                   policy + physics                (relays, sensors)    (tank level, chlorine)
                       │
                  held commands
                       ▼
                    AGENT ──► operator briefing ──► Approve / Reject ──► incident report

What’s real and what’s simulated: the Modbus traffic, the gateway, the block, the relays, the sensors and the alarm are real. The tank level and chlorine are computed by the twin, and the ESP32 stands in for an industrial controller.


Running It Locally

python -m venv .venv
.venv\Scripts\Activate.ps1          # Mac/Linux: source .venv/bin/activate
pip install -r requirements.txt
python tasks.py demo --sim          # software station, twin and gateway; drop --sim to use the ESP32

Open http://localhost:8000 and sign in as operator. In a second terminal, run an attack:

python -m attacks.normal_day           # allowed
python -m attacks.chlorine_overdose    # held, with the physics reason

There are six scenarios in attacks/: normal day, chlorine overdose, drain the town, overflow, logic tamper and operator on site. Only run them against your own station or the software station. The register map is in shared/registers.yaml, the site is documented in dashboard/README.md, and the firmware in firmware/README.md. python tasks.py test runs the test suite.