Every hardening sprint, written down in full.
tun-el is partly a hosted service. You trust us with your tunnels, sometimes with your data. We believe radical transparency about security — including what is not yet covered — is the best way to earn that trust.
Timeline
9 entries- 2026-05-29Sprint 8MAR-94
Abuse detection + auto-revoke
Sprint 7 laid down the traversing rate limit — passive detection. Sprint 8 enforces: in-memory behavioral tracker, per-token accumulation of denials over a sliding window, auto-revoke plus teardown of active tunnels past threshold. 18 paranoid security tests (per-token isolation, idempotence under race, GC never touches a revoked entry, nil-safe). Zero regressions.
abuseauto-revokebehaviorauditRead the full write-up - 2026-05-29Sprint 7MAR-93
Traversing HTTP rate limit (3 axes)
Before: HTTP requests flowing through the tunnels were not rate-limited — abusive bandwidth, hotlinking, pass-through DDoS. Sprint 7 introduces a 3-axis rate limit (tunnel + token + IP) with an IP → tunnel → token short-circuit to avoid amplification, configurable env vars, and a dedicated audit event.
rate-limitddosabuseauditWrite-up coming - 2026-05-28Sprint 6MAR-70
Token peppering on self-host
On the SaaS side, the pepper had been active since init. On self-host (tokens.json), the hash was a bare SHA-256(secret). Sprint 6 extends Store to accept an optional pepper via TUNL_TOKEN_PEPPER, backward compatibility preserved bit-for-bit, fail-loud on invalid format.
tokensself-hostdefense-in-depthWrite-up coming - 2026-05-28Sprint 5MAR-100
Persistent error logging on SaaS
Capture of errors surfaced in app/error.tsx into a Supabase table indexed by digest, with full context (message, stack, path, user_id, user_agent). Strict RLS (INSERT service_role only, SELECT own), per-field truncation, fire-and-forget on the client.
observabilitysupabaseserver-actionsWrite-up coming - 2026-05-28Sprint 4MAR-71
Strict protocol-version check at handshake
Clean reject of an incompatible client (instead of a crash after the handshake), a transport-side error sentinel to tell a version mismatch apart from an auth failure, a clean client-side exit instead of reconnect spam, and a WARN audit event to drive version bumps.
protocolhandshakefail-fastauditWrite-up coming - 2026-05-28Sprint 3MAR-69
Strict CSP on the embedded inspector
Removal of every third-party resource (Tailwind CDN, Google Fonts), self-hosting of the Geist Variable fonts, full de-inlining of JS and CSS, and a 9-directive CSP applied to every route — assets and API included.
cspinspectorfrontendsupply-chainWrite-up coming - 2026-05-28Sprint 2MAR-66MAR-67MAR-68
Edge hardening and security observability
Systematic 308 → HTTPS redirect, security headers HSTS preload + nosniff + X-Frame-Options + Referrer-Policy (Go and Next.js aligned), and a structured JSON Lines audit log covering sensitive events.
httpshstsaudit-logWrite-up coming - 2026-05-27Sprint 1MAR-61MAR-62MAR-64
Control-plane hardening
WebSocket origin check, handshake rate-limiting, tunnel quotas, elimination of a subtle race on subdomain allocation, and a memory bound on the handshake.
websocketrate-limitingWrite-up coming - 2026-05-27Audit
SAST audit — gosec + Semgrep + CodeQL
Static analysis of the Go code with three complementary tools. Every finding triaged true/false positive, justified, and linked to its fix.
sastgosecsemgrepcodeqlWrite-up coming
The full chain, from code to production.
Every layer is traced, every tool is replayable, every run is archived. Target: MAR-106.
Source code
SAST
- Semgrep
- gosec
- staticcheck
Source code
Data flow
- CodeQL
- Bearer
Source code
Semantic
- Joern
- Qwiet
Supply chain
Deps & CVE
- govulncheck
- Trivy (fs + binary)
- Grype
- Syft (SBOM)
Runtime
Tests
- go test -race
- go fuzz
Runtime
DAST (black box)
- OWASP ZAP
- Burp Suite
- Nuclei
AI review
Automated reviews
- Claude /ultrareview
- Vercel Agent
- GPT-5
Audit log
11 runs archived · latest 2026-06-05T19:21docs/security/AUDIT-LOG.md
| Timestamp | Run | Author | Verdict |
|---|---|---|---|
| 2026-06-05T19:21 | turbo | Frédéric Margerit | pass |
| 2026-06-01T14:53 | supply-chain | Frédéric Margerit | pass |
| 2026-05-31T19:32 | supply-chain | Frédéric Margerit | pass |
| 2026-05-29T02:30 | sprint-8 | Frédéric Margerit | pass |
| 2026-05-29T01:10 | sprint-7 | Frédéric Margerit | pass |
| 2026-05-29T00:30 | sprint-6 | Frédéric Margerit | pass |
| 2026-05-28T23:55 | sprint-5 | Frédéric Margerit | pass |
| 2026-05-28T23:30 | sprint-4 | Frédéric Margerit | pass |
| 2026-05-28T22:00 | sprint-3 | Frédéric Margerit | pass |
| 2026-05-28T11:00 | sprint-2 | Frédéric Margerit | pass |
| 2026-05-27T20:24 | turbo | Frédéric Margerit | pass |
Append-only. Every run is versioned in the repository under docs/security/audits/<date>/ with its raw outputs (SARIF, JSON) and a run.json manifest.
Why this page?
tun-el is partly a hosted service. You trust us with your tunnels, sometimes with your data. We believe radical transparency about security — including what is not yet covered — is the best way to earn that trust. The complete reports are also versioned in the upcoming public repository, under docs/security/.