Documentation

Installing, configuring and running OpenWhistle, the free platform for self-hosted whistleblowing under HinSchG and EU Directive 2019/1937.

A stateless, self-hosted web application: the secure internal reporting channel that the German Hinweisgeberschutzgesetz (HinSchG) and EU Directive 2019/1937 require. Licensed under the GNU General Public License v3.0.

Python and FastAPI, PostgreSQL 18 and Redis 8, shipped as a Docker image. No CDN and no third-party service; every outbound request is opt-in and listed in full.

Beside GlobaLeaks, SecureDrop and Hush Line: open source whistleblowing software compared.

Key design principles

  • Anonymity first: no IP address is stored at any layer (four layers).
  • Stateless: all session state lives in Redis; the app container is disposable and scales horizontally.
  • Compliance by design: the §17 HinSchG deadlines are part of the data model.
  • No lock-in: standard Docker Compose; your data is plain PostgreSQL.

Supported platforms

  • Any Linux host with Docker 24+ and Docker Compose v2
  • x86_64 and ARM64 (Apple Silicon): images for linux/amd64 and linux/arm64
  • Registries: GitHub Container Registry (ghcr.io), Docker Hub, Quay.io

Current version

v2.4.0. What it changed:

  • An admin brands the reporter's pages on /admin/branding: name, a light and a dark logo, the brand colour, per organisation.
  • Every page links the external reporting offices (§13 Abs. 2 HinSchG) and, when set, the operator's privacy and legal notice.
  • A reporter whose request carried address headers is told the server in front may log the address.
  • No public page names the release; signed-in admins see it in the footer.
  • The reporter and admin pages got a design pass, and LDAP refuses to start without TLS.

What v2.3.0 changed:

  • The app wears the website's design: the same type, colours, navigation and footer.
  • After an update, the dashboard asks an admin once whether to count the installation, while counting is off.
  • The audit log filters and names cases by their case number.
  • Every image is scanned for known vulnerabilities before it is published.
  • Forty fixes from a bug bounty, listed in the changelog.

What v2.2.1 changed:

  • Encrypted values no longer carry the second they were written; stored reports are re-sealed.
  • Attachments are stored with the type their extension names; Office files embedded in Office files are cleaned too.
  • The demo has a second admin, demo2, so a four-eyes deletion can be tried.
  • Seventeen fixes from a bug bounty, listed in the changelog.

What v2.2.0 changed:

  • The interface speaks Spanish, its fifth language, chosen for a browser that asks for it.
  • Statistics write percentages the way the admin's language does, and the page for invalid input is translated.

What v2.1.1 changed:

  • A new logo, and each theme tells the browser whether it is light or dark, so Chrome's Auto Dark Mode leaves the light theme alone.
  • Colours, code samples and the footer meet WCAG AA contrast in both themes.
  • No page is wider than a 360 px phone.

What v2.1.0 changed:

  • Every admin changes their own password and links their own single sign-on; a lost authenticator can be reset.
  • The §17 HinSchG deadlines follow the statute, from receipt, in calendar months.
  • Attachments lose their metadata without a pixel changing.
  • A superadmin gives each organisation its own admins.
  • Over forty fixes from a bug bounty, listed in the changelog.

What v2.0.1 changed:

  • The first account is a superadmin, so organisations can be managed.
  • Pages that fit the window no longer scroll past it.

What v2.0.0 changed:

  • The confidential identity is shown only to the handler, with an audited reason.
  • The first-run setup needs a one-time token.
  • Whistleblower times are stored as the day only.
  • An optional Tor onion address and ClamAV upload scan.
  • TLS by default in the Compose stack.
  • An opt-in installation count, off by default.
  • Words inside reports are searchable without an index.

Every change: Changelog.

Edit this page on GitHub