Belkins BirdNET is a LAN-first appliance: a Raspberry Pi and a USB microphone that listens for birds, names them with Cornell's BirdNET, and paints each one into a live kachō-e collage. It is meant to run quietly on your home network, not to face the public internet. This document explains what we support, how to report a vulnerability, and how the box is hardened.
Belkins BirdNET is an appliance, not a versioned software product. There are no
tagged releases or long-lived release branches to backport fixes to. The supported
line is simply the main branch — the code the installer pulls when you run it,
and the code a re-run of the installer converges you back onto.
| Line | Supported |
|---|---|
main (latest) |
✅ Yes |
| Older checkouts / forks |
If you are on an older checkout, the fix for almost anything is to pull main and
re-run the installer. It is additive, idempotent, and self-heals the security-relevant
configuration described below.
Please report privately. Do not open a public GitHub issue for a security problem.
Two private channels, either is fine:
- GitHub → the repo's Security tab → "Report a vulnerability" (private vulnerability reporting). This is the preferred route — it keeps the report, the discussion, and the fix in one place.
- Email vladislav@belkins.io if you'd rather not use GitHub.
A useful report includes what you found, where (file, endpoint, or install step), how to reproduce it, and what an attacker could do with it. Proof-of-concept steps are welcome.
We are a small team, so please set expectations accordingly: we aim to acknowledge a
report within a few days, confirm the issue, and work a fix on main. We'll keep
you in the loop and are glad to credit you once a fix has shipped, if you'd like.
Please give us a reasonable window to fix things before disclosing publicly.
Belkins BirdNET is designed to be a local-first, unattended appliance on a trusted LAN. Two properties are worth understanding before you deploy it:
The public PHP surface runs unprivileged. The Caddy web server and the PHP-FPM
pool that serve the collage and the admin overlay run as the low-privilege caddy
user — not as root. That user is granted a least-privilege sudoers allowlist:
only the exact systemctl restart … and journalctl -u … commands on the BirdNET
service units that the admin overlay actually calls. It is not blanket root. A
prior blanket NOPASSWD: ALL rule was removed, and the installer deletes it on every
run — so an already-installed box self-heals the moment the installer re-runs. The
intent is that even a bug in a PHP endpoint cannot escalate to a full-root RCE.
It is not meant for the public internet. The appliance assumes a trusted home network and has no built-in authentication on the collage itself. Do not expose the Pi directly to the internet. If you need remote access, put it behind a reverse proxy that terminates TLS and enforces authentication, and harden the box first. The bundled Cloudflare Tunnel recipe is a convenience, not a hardening layer — the same "add auth in front of it" advice applies.
The LAN gate is a single, owner-controlled switch. Since 2026-07-27 the admin
plane (config, service controls, the database, the terminal) sits behind Caddy
basic_auth plus a PHP auth layer, both keyed on CADDY_PWD in birdnet.conf —
fail-closed: an empty password refuses rather than opens. STATION_OPEN="1" in
birdnet.conf stands both layers down deliberately — the owner of this station
typed that choice on 2026-07-30 so the household can reach everything without a
password; Host pinning stays on either way. If that trade is not yours to make, run
closed: set STATION_OPEN="0" (or leave it unset) and both layers enforce. The
restore path after an open period is STATION_OPEN="0" plus re-running the installer.
A few practical notes:
- Keep the Pi on your LAN; reach it at
http://birdnet.local/. - The optional off-LAN forwarding recipes (Cloudflare / Home Assistant / MQTT) and the auto-gen forwarder send data outward — review each before enabling it, and note that the Gemini API key for auto-generation lives only on the Railway service, never on the Pi.
- Re-run the installer after updating so the sudoers allowlist and other config stay in their intended, least-privilege state.
In scope — the code this project adds and operates:
- The PHP API surface under
avian/api/(e.g. the cutout resolver and status/admin endpoints) and the collage frontend it serves. - The installer and its service/
sudoers/Caddy configuration (scripts/install_services.shand friends). - The realtime spine and forwarder (
avian/realtime/) and the on-demand generator service (services/birdgen/).
Out of scope — upstream projects we build on. Please report these to their maintainers:
- BirdNET-Pi (Nachtzuster · Patrick McGuire) — the recording and detection foundation. Issues in stock BirdNET-Pi code belong upstream.
- The BirdNET model — © the K. Lisa Yang Center for Conservation Bioacoustics, Cornell Lab of Ornithology. Model behaviour and accuracy questions go to Cornell, not here.
- The live-collage concept was inspired by AvianVisitors (Twarner491).
If you're unsure whether something is ours or upstream, report it to us anyway — we'd rather triage it than have it fall through the cracks.
Belkins BirdNET is distributed under CC-BY-NC-SA 4.0, inherited from BirdNET-Pi and Cornell's BirdNET. Reporting a vulnerability, like everything else here, is a non-commercial, good-faith contribution — thank you for helping keep the gallery safe.