about

  • 15,962 cameras
  • 14 users
  • 362 games played

insecure.camera started out as an idea for CamGuessr, inspired by VNC Roulette. That needed a database of cameras, which needed a scanner, which needed a viewer, and before long it had expanded into a whole site. The point is to raise awareness about just how insecure these devices are.

discovery

Cameras are discovered using zmap, which scans the public IPv4 address space for hosts with port 554 (RTSP) open. This runs on a schedule, continuously finding new cameras and re-checking known ones.

The results are piped into viewfinder, a Go service that takes in a list of IPs and probes each one for valid RTSP streams. It tries common stream paths and checks whether the camera responds without requiring authentication. If a camera asks for credentials, we disconnect immediately, we don't try default passwords or common logins like admin:admin.

ingestion

Once a potential camera is found, it's handed off to ffmpeg to capture a thumbnail. The IP is geolocated using ipinfo, and the camera is inserted into the database. If a camera is already known, its metadata and thumbnail are updated.

Cameras that stop responding are not immediately removed, they stay listed until they haven't been seen for a while. This accounts for cameras that go offline temporarily.

the stream proxy

Browsers can't play RTSP streams natively, so the API server acts as a proxy. When you watch a camera, the server spawns an ffmpeg process that connects to the RTSP stream and remuxes it into HLS. The HLS segments are uploaded to S3 and served to your browser as a standard video stream. Because ffmpeg remuxes the stream without re-encoding (-c copy), this uses basically zero CPU.

The tradeoff of remuxing without re-encoding is that the stream data is passed through as-is. If a camera outputs a malformed or non-standard stream, there's nothing to clean it up along the way, the broken data goes straight to your browser, which can cause the player to fail or refuse to play entirely. Re-encoding would fix these streams at the cost of significant CPU, so for now some cameras just won't work.

The proxy also reduces load on the cameras. No matter how many people are watching, the server only maintains a single connection to the camera. Everyone shares the same HLS segments from S3 rather than each opening their own RTSP connection directly.

the stack

  • SvelteKit frontend with Tailwind CSS and shadcn-svelte
  • Go API server using Echo
  • PostgreSQL database
  • S3-compatible object storage (MinIO)
  • ffmpeg for stream transcoding and thumbnail capture
  • zmap for network scanning