A ~$40 ESP32-S3 e-paper gadget that pulls live CVE / exploit / bug-bounty / infosec-news feeds straight from the Vulners API and forecasts the threat "weather" — so you can stop refreshing notifications, mail, and JSON for vulnerability alerts. It watches, so you don't have to. Fully on-device. No backend, no server.
The dashboard: a featured champion + candidate feed, with sync age, API status, and the live web-interface IP in the top bar.
No build, no esptool — grab the board, click once, done.
- 🛰️ Direct-to-API, on-device. Per-channel Lucene search + on-demand by-id detail, straight from
firmware with an
X-Api-Keyheader. No proxy, no companion app. - 📡 Rotating channels. News · Exploits · Bug Bounty · Vulnerabilities out of the box — plus any custom channel (just a Lucene query + refresh interval).
- 🧬 Human-first document view. CVSS decoded into exploitability icons + C/I/A impact bars, CWE / CISA-KEV chips, an exploit count, a scrollable summary, and a scannable QR deep-link — the layout adapts per record type (CVE vs exploit vs advisory).
- 🖥️ Touch UI. Dashboard, document, settings, on-screen keyboard, refresh-interval and time-zone pickers, plus firmware-update and out-of-credits screens — GT911 capacitive touch, saved to NVS.
- 😌 Chill mode. A lofi grayscale screensaver — a cat at a desk reading the live CVE feed, a drifting sailboat out a seaside window, and real-time clocks — kept flash-free on e-paper. Tap the Vulners logo five times to enter; one tap to leave.
- 🪙 API credits, in view. Your remaining Vulners API credits sit in the dashboard footer, with a full-screen heads-up (and a QR to upgrade) the moment they run out.
- 📶 Zero-config Wi-Fi. WPA2/WPA3, multi-network store, captive-portal provisioning, and a runtime fallback to the setup AP if the network disappears.
- 🎞️ Flash-free e-paper. A damage-tracking compositor repaints only the changed rows (2-bit partial update) — no full-screen blink on every tick.
- 🔄 Signed over-the-air updates. Checks GitHub hourly — or on demand from Settings → Check for updates — verifies an Ed25519 signature on the release manifest, installs on your confirmation, and rolls back automatically if the new build doesn't boot cleanly. Plus a factory-reset button that wipes the device back to out-of-box state.
- Board: LilyGo T5 4.7" E-Paper S3 V2.4 (ESP32-S3-WROOM-1-N16R8 — 16 MB flash, 8 MB OPI PSRAM, 240 MHz, dual-app OTA partitions). ~$40 — pick the Touch variant.
- Panel: 960×540 ED047TC1 e-paper (rendered 2-bit) with a GT911 capacitive touch controller.
- ESP32-S3 is 2.4 GHz Wi-Fi only. Native USB may re-enumerate on reset — that is normal.
- Platform: pioarduino — Arduino-ESP32 3.x / ESP-IDF 5.5.
- Display: FastEPD drives the V2.4 shift-register panel; epdiy 2.0 is the software rasterizer. A 960×540 4bpp framebuffer lives in PSRAM; a damage-tracking compositor repaints only the changed rows (flash-free 2-bit partial update) — a full flash runs only on a page/data change and a periodic de-ghost.
- Data: the Vulners REST API over HTTPS, parsed with ArduinoJson filters using precise dot-notation field selection, so even multi-MB documents stay small.
- Wi-Fi: WPA2/WPA3, multi-network NVS store, captive-portal provisioning (
vulncast.local). - Update: USB, password-protected OTA (ArduinoOTA), and signed background auto-update from GitHub with automatic rollback — see Firmware updates below.
Every ~hour the device anonymously fetches a small signed manifest from GitHub Pages
(update.json: version, image URL, size, SHA-256, and an Ed25519 signature). It verifies the
signature against a public key baked into the firmware, and if a newer version is offered it shows
an update screen — Update now or Try again tomorrow. On confirmation it streams the app image,
checks the SHA-256 against the signed value, and writes it to the spare OTA slot.
The new build then boots in a pending-verify state: it must reach a live UI without crashing, or the bootloader rolls back to the previous version automatically (with an on-device "update failed" screen). A three-strikes boot counter backstops a hard wedge. TLS to GitHub is validated against the embedded CA bundle, but the Ed25519 signature is the real integrity gate — a compromised CDN, cert, or TLS link still cannot ship firmware the device will run. No credentials are baked in; the private signing key lives only on the release machine.
Configuration (for forks — override in platformio.ini build_flags, defaults are secure):
| Flag | Default | Effect |
|---|---|---|
VULNCAST_UPDATE_MANIFEST_URL |
our GitHub Pages update.json |
Point auto-update at your own host. |
VULNCAST_OTA_REQUIRE_SIGNATURE |
1 |
0 runs signature-free — for a fork that self-hosts updates without managing a signing key (integrity then rests on TLS + the manifest SHA-256). |
VULNCAST_OTA_CHECK_INTERVAL_MS |
3600000 |
How often to check. |
To cut a signed release: build the credential-free app image (firmware.bin, not the .factory.bin)
and the browser-flasher factory image, drop both under flasher/firmware/, then
python3 scripts/sign_manifest.py --version X.Y.Z --url https://vulnerscom.github.io/VulnCast/firmware/vulncast-X.Y.Z-app.bin --bin flasher/firmware/vulncast-X.Y.Z-app.bin --out flasher/update.json
and push — GitHub Pages serves update.json + the app image (single origin, no redirect). The private
key is read from ~/.vulncast/ (generated once by scripts/gen_update_key.py) and is never committed.
The easiest path: flash from your browser →. Plug the board in over USB-C, click once, and ESP Web Tools writes the firmware over Web Serial — no toolchain, no compiler. Needs desktop Chrome / Edge / Opera.
The flasher (page + manifest + firmware) is self-hosted from this repo under
flasher/ and published to GitHub Pages. The shipped binary is credential-free — you
enter Wi-Fi and your Vulners API key on the device via the captive portal; nothing is baked in.
Prefer the CLI? Flash the same image with esptool:
esptool.py --chip esp32s3 write_flash 0x0 flasher/firmware/vulncast-1.1.4-esp32s3.factory.binVerify the image first — SHA-256 of vulncast-1.1.4-esp32s3.factory.bin:
d5a6d989e212cb3b9ee1c9dc0c177482fdb70f63d7d55cfe3b946e5f8286ee15
Requires PlatformIO Core (≥ 6.1.18) and a Vulners API key.
cp secrets.yaml.example secrets.yaml # fill vulners_api_key (+ optional wifi seed / ota_password)
pio run # compile (generates include/secrets.h from secrets.yaml)
pio run -t upload # flash over USB
pio device monitor # serial logs @115200On first boot with no known Wi-Fi in range, the device raises a VulnCast-Setup hotspot — join it,
open http://192.168.4.1, pick your network and enter your API key. Everything (Wi-Fi, key, channels,
time zone) is stored in NVS; secrets.yaml only seeds a first-boot fallback and is never committed.
An always-on UART console runs on its own core-0 task (it answers even if the UI loop is busy). Drive
it from the host with tools/console.py (pip install pyserial pillow):
python tools/console.py info # device state (wifi, api key, channels, heap)
python tools/console.py dump fb.png # capture the exact e-paper framebuffer as a PNG
python tools/console.py press featured # inject a touch at a named hit-box
python tools/console.py reboot| Path | What |
|---|---|
src/ |
Firmware: orchestration, touch UI + chill-mode screensaver, drawing toolkit, Vulners client, channels, Wi-Fi, timekeeper, config, updater, web UI. |
boards/T5-ePaper-S3.json |
Board definition (vendored from LilyGo) for the exact V2.4 module. |
scripts/gen_secrets.py |
Pre-build hook: generates include/secrets.h from secrets.yaml. |
tools/ |
Host tooling: serial console, framebuffer dump, font/asset generation. |
- Contributor guide → CONTRIBUTING.md
- Security policy & reporting → SECURITY.md
Fonts: JetBrains Mono (OFL 1.1). Libraries: FastEPD · epdiy · ArduinoJson · SensorLib · Button2 · QRCode. Full attribution in THIRD_PARTY_NOTICES.md.
A Vulners Inc. project, powered by the Vulners API. Not affiliated with or endorsed by LilyGo.
MIT © 2026 Vulners Inc.
Built with ⚡ by Vulners
#ESP32 #ESP32S3 #ePaper #eInk #LilyGo #PlatformIO #Arduino #Vulners #CyberSecurity
#InfoSec #VulnerabilityManagement #CVE #ThreatIntel #IoT #EmbeddedSystems #DevSecOps







