NSFW-Guard

A fully local, offline NSFW screen-content guard for GNOME/Wayland Linux. Uses a local NudeNet ONNX model in a sandboxed Docker container to keep children safe online.

Overview

NSFW-Guard watches the screen using a Docker container (with --network none) and a local NudeNet ONNX model. When explicit content is confirmed during a configured time window (default 22:00–07:00), it shows a full-screen warning with a countdown — and if the content is still on screen when the grace period (5 seconds) expires, it logs the GNOME session out. Closing the content cancels the logout.

No network calls at runtime, no cloud service, no telemetry. Everything runs on your own GPU/CPU inside a sandboxed container.

Architecture

Two parts, because a sandboxed container can't directly draw overlays or end a GNOME session:

  • The container: Does all the sensitive work — screen capture (xdg-desktop-portal + PipeWire), NudeNet inference, thresholds, the active-hours clock, and the decision to warn and log out. Network is disabled entirely.
  • The GNOME Shell extension: Listens on a bind-mounted Unix socket for three messages: warn (full-screen overlay + CRITICAL notification), cancel (content removed during grace period), and logout (triggers gnome-session-quit --logout --no-prompt).

The only communication between container and host is through this Unix socket — no network, no DBus, no shared memory.

How It Works

A simple state machine: IDLE → WARNING → LOGOUT.

  • Screen is captured at regular intervals
  • Each frame is classified by the NudeNet ONNX model
  • If explicit content is detected and current time is within the configured window: warning appears with a 5-second countdown
  • If content is removed before timer expires: state returns to IDLE
  • If timer expires: GNOME session is logged out

Technologies

Python NudeNet ONNX GNOME Shell Extensions Docker PipeWire vibe coded

Interesting Details

  • The container runs with network_mode: "none" — it has no internet access at all
  • The GNOME Shell extension is intentionally dumb: it only knows how to show/hide a warning overlay and trigger logout
  • Active hours are configurable (default: 22:00–07:00)
  • All inference logic and timing lives inside the container, not the extension