RunWisp

Security

Canonical policy lives in SECURITY.md in the repository. This page summarises the parts most operators care about.

Reporting a vulnerability

Email [email protected] with a description and reproduction steps. Do not file a public issue for security bugs. You'll get an acknowledgment within days and a triage within two weeks. Reporters are credited in the release notes unless they prefer to stay anonymous.

Trust boundaries

The daemon runs with the caller's privilege. Two inputs, two trust levels:

  • runwisp.toml is trusted. It runs arbitrary commands — treat it like a shell script. Protect it with file permissions.
  • The REST API and Web UI are untrusted. They can trigger defined tasks and read run history, but cannot mutate the config or execute arbitrary commands.

Authentication

Two auth paths, both opt-in:

  • Local (Unix socket): Peer UID verified via SO_PEERCRED / LOCAL_PEERCRED. No password needed for local CLI and TUI access.
  • Remote (HTTP): Challenge-response CHAP with a JWT session. Signing key derived via HKDF-SHA-256 at startup, never written to disk. Password comes from RUNWISP_PASSWORD env only.

Release integrity

Every tagged release ships with:

  • SHA-256 checksums for every binary in checksums.txt, attached to the GitHub Release.
  • OIDC Trusted Publisher for npm packages — no hardcoded tokens in CI. Each platform package authenticates via GitHub Actions' OIDC identity.
  • Two-stage release: CI builds and creates a draft release; a human reviews and publishes it. No automated push to production.

Not yet in place (roadmap for 1.0): GPG-signed binaries, SBOM generation (CycloneDX), and SLSA build provenance. These are planned — not shipped.

Supply chain

  • Pure-Go SQLite via modernc.org/sqlite — no CGo, no system library dependency.
  • Single static binary — no runtime, no interpreter, no container needed.
  • CI on every PR: lint, type-check, unit tests, and Playwright E2E tests on Ubuntu and macOS.

Deployment hardening

Recommendations from the project's security policy:

  1. Set the data directory to 0700. It contains the SQLite database, run logs, and derived secrets.
  2. Set RUNWISP_PASSWORD if the HTTP listener is reachable from a network.
  3. Bind to 127.0.0.1 (the default) unless you need remote access.
  4. When running behind a reverse proxy, set trust_proxy to the proxy's CIDR.
  5. Run the daemon as an unprivileged user.
  6. Stay current — pre-1.0, only the latest release receives security fixes.

What's in scope

Auth bypass, socket trust bypass, session/JWT flaws, path traversal, TOML parser bugs, proxy header misuse, insecure defaults, and vulnerabilities in direct dependencies.

What's out of scope

Arbitrary command execution via runwisp.toml (by design), data-dir access (trust boundary), operator-initiated DoS, missing HTTP headers for reverse proxy setups, and missing rate limits on loopback.

Questions

Security concerns: [email protected]. Everything else: GitHub Issues.