Skip to content

Security

Dungbeetle is source-available and built to a simple rule: keep the attack surface small enough to reason about, and defend in depth behind it. The hosted service is multi-tenant, so isolation, encryption, and auditability are designed in — not bolted on. This page is the honest picture of how that works, not a certification.

Reporting a vulnerability

Please don't open a public issue for a security problem. Report it privately through the repository's Security → Report a vulnerability tab (GitHub private reporting), or email the maintainer.

Include the affected component, the version or commit, and a minimal reproduction if you have one. We aim to acknowledge within a few business days, agree a disclosure timeline, and credit you once a fix ships. See SECURITY.md for the full policy.

How your data is protected

  • 🔐 Tenant isolation — every read and write is SQL-scoped to your repository and team; a request for another tenant's resource returns 404, never a leak. Locked in place by a dedicated isolation test suite.
  • 🧬 Secrets and data are encrypted — passwords are hashed with scrypt, API tokens and client secrets are stored as SHA-256 (optionally HMAC-peppered), and stored blobs can be sealed at rest with AES-256-GCM.
  • 🧱 Injection-resistant by construction — SQL runs only through bound parameters, HTML is escaped under a strict nonce-based Content Security Policy, and every uploaded artifact is verified against its claimed SHA-256 digest.
  • 🪪 Hardened authentication — opaque HttpOnly session cookies with an absolute lifetime, rate limiting per IP and per account, PKCE + state on OAuth sign-in, and constant-time comparison of every secret.
  • 🚦 Safe by default — quotas are enforced server-side, retention is pruned, and startup fails fast rather than run misconfigured (a sealed database with no key, or an incomplete storage config, refuses to boot). The server only ever calls operator-configured endpoints — never a tenant-supplied URL.
  • 🧾 Tamper-evident — GCM authentication tags reject any modified blob, incoming webhooks are HMAC-verified, and every auth, credential, and ingest event is written to a structured JSON audit log (actor, IP, outcome — never secret material).
  • 📦 Guarded supply chain — a deliberately small dependency set, weekly automated dependency updates, CodeQL scanning, npm audit gating CI, secret scanning across the full git history, DCO-signed commits, and npm publish provenance.

A small, auditable surface

Most of Dungbeetle runs on the Node.js standard library — SQLite via node:sqlite (no native driver), crypto via node:crypto, OAuth over the built-in fetch. There is no ORM, no template engine, and no telemetry or analytics SDK. What's left is a short, purpose-built list you can audit in an afternoon:

CLI (dungbeetle) — runs on a developer's machine or CI:

  • commander — parses the CLI's arguments and subcommands.
  • parse5 — spec-compliant HTML parsing for DOM capture without a browser.
  • playwright-core — the optional real-browser driver, used only when you opt into browser-backed web or screenshot capture.
  • pngjs — decodes and compares PNG screenshots.
  • zod — validates your config and game-walkthrough files.

Server (dungbeetle-server) — runs the hosted / self-hosted service:

  • hono + @hono/node-server — the HTTP router and its Node adapter.
  • @modelcontextprotocol/sdk — the MCP integration for agent workflows.

Under the hood

Exact versions and current test coverage for both projects, generated straight from the source so they can't drift (npm run docs:security-facts):

CLI — dungbeetle

Requires Node >=22.5.0.

Test coverage — Lines 88.9% · Statements 88.8% · Functions 93.0% · Branches 75.4%

Runtime dependencies

PackageVersion
commander^15.0.0
parse5^8.0.1
playwright-core^1.61.1
pngjs^7.0.0
zod^4.4.3
Dev & build dependencies
PackageVersion
@biomejs/biome2.5.1
@types/node^26.0.1
@types/pngjs^6.0.5
@vitest/coverage-v8^4.1.9
esbuild^0.28.1
tsx^4.22.4
typescript^6.0.3
vitest^4.1.9

Server — dungbeetle-server

Requires Node >=22.5.0.

Test coverage — Lines 90.9% · Statements 90.5% · Functions 92.8% · Branches 74.4%

Runtime dependencies

PackageVersion
@hono/node-server^2.0.6
@modelcontextprotocol/sdk^1.29.0
hono^4.6.14
Dev & build dependencies
PackageVersion
@biomejs/biome2.5.1
@types/node^26.0.1
@vitest/coverage-v8^4.1.9
asciinema-player^3.16.0
mermaid^11.16.0
playwright^1.61.1
tsx^4.22.4
typescript^6.0.3
vitepress^1.6.4
vitepress-plugin-mermaid^2.0.17
vitest^4.1.9

Operating it securely

Some controls live in your deployment, not the code:

  • Rate limiting is per-process. Front a multi-instance deployment with a shared limiter or an edge/WAF rate limit.
  • Encryption key and pepper (DUNGBEETLE_ENCRYPTION_KEY, DUNGBEETLE_CREDENTIAL_PEPPER) must be supplied and kept stable — the server refuses to start if sealed data exists without its key.
  • TLS is expected at the server or a reverse proxy; set DUNGBEETLE_SECURE_COOKIES=true when terminating TLS upstream.
  • Audit logs are written to stdout — capture and retain them in your log pipeline for alerting.

See the cloud server security posture for the operator-facing detail, and the self-hosting guide for deployment.

OWASP Top 10 traceability

Full control-to-test mapping (for auditors)

The controls above map to the OWASP Top 10 (2021) as follows. Paths are relative to the server repository root; CLI-only concerns are out of scope for the multi-tenant service.

OWASP categoryHow it's addressedWhereTests
A01 Broken Access ControlEvery API route resolves repositoryId from client credentials and 404s on a foreign resource; the web UI's repoGuard verifies a team_memberships row for the repository's account_id; store reads are SQL-scoped by repository_id / account_id.src/app.ts, src/web.ts, src/store/test/tenant-isolation.test.ts, test/web.test.ts
A02 Cryptographic Failuresscrypt password hashing; API tokens & client secrets stored as SHA-256 (optionally HMAC-peppered); blobs sealed at rest with AES-256-GCM; HSTS only when terminating TLS.src/crypto.ts, src/blobs.ts, src/app.tstest/blobs.test.ts, test/security.test.ts, test/auth.test.ts
A03 InjectionBound-parameter SQL only; escaped HTML under a strict nonce-based CSP; base64-validated inline screenshots and digest-verified artifact uploads.src/store/, src/views/, src/validate.tstest/sql-injection.test.ts, test/security.test.ts
A04 Insecure DesignServer-side quota enforcement; retention pruning; fail-fast startup on a sealed store without a key or an incomplete S3 config.src/billing.ts, src/store/blobService.ts, src/blobstore.tstest/enforcement.test.ts, test/startup-config.test.ts
A05 Security MisconfigurationCSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, COOP, HSTS; HttpOnly + SameSite=Lax (+ Secure) cookies; no secrets baked in; fail-fast on misconfiguration.src/views/, src/app.ts, src/runtime.tstest/security.test.ts, test/startup-config.test.ts
A06 Vulnerable & Outdated Componentsnpm audit --audit-level=high gates CI; Dependabot (weekly); CodeQL security-and-quality; CycloneDX SBOM artifact..github/workflows/ci.yml, .github/workflows/codeql.yml, .github/dependabot.ymlCI
A07 Identification & Auth FailuresOpaque session cookies with absolute TTL; failed-auth rate limiting per IP and per account; constant-time credential & OAuth-state comparison; OAuth PKCE + state.src/web.ts, src/rateLimit.ts, src/oauth.ts, src/crypto.tstest/auth.test.ts, test/security.test.ts
A08 Software & Data Integrity FailuresHMAC-SHA256 webhook verification with a timestamp tolerance; GCM auth tag rejects tampered blobs; secret scanning; DCO-signed commits; npm publish provenance.src/stripe.ts, src/blobs.ts, .github/workflows/test/stripe.test.ts, test/blobs.test.ts
A09 Security Logging & Monitoring FailuresStructured JSON audit log for every auth/credential/ingest/billing event, with actor + IP + outcome and no secret material.src/audit.tstest/security.test.ts
A10 Server-Side Request Forgery (SSRF)Outbound requests go only to operator-configured endpoints (OAuth providers, the S3 backend) — never a tenant-supplied URL.src/oauth.ts, src/blobstore.ts— (by design)

Source-available: CLI under FSL-1.1-ALv2, cloud server under BUSL-1.1. See Licensing.