ivx research Disclosure Architecture
Architecture
Overview
Disclosure is a single-binary Go application that serves an HTML web interface and ActivityPub federation endpoints. It uses SQLite for storage and NaCl (libsodium) for end-to-end encryption.
┌─────────────────────────────────┐
│ Disclosure Server │
│ │
│ ┌───────────┐ ┌────────────┐ │
│ │ Web UI │ │ ActivityPub│ │
│ │ (HTTP) │ │ Endpoints │ │
│ └─────┬─────┘ └─────┬──────┘ │
│ │ │ │
│ ┌─────┴──────────────┴─────┐ │
│ │ Service Layer │ │
│ │ Actor │ Report │ Program│ │
│ └────────────┬─────────────┘ │
│ │ │
│ ┌────────────┴─────────────┐ │
│ │ SQLite Database │ │
│ └──────────────────────────┘ │
└─────────────────────────────────┘
Key components
Web interface
The web interface is server-rendered HTML using Go templates and Tailwind CSS. It provides:
- Dashboard — Overview of reports and programs
- Report submission — End-to-end encrypted report forms
- Program management — Create and configure bug bounty programs
- Access control — Grant and request access to encrypted reports
- Notifications — Real-time notifications for status changes
ActivityPub federation
Disclosure implements ActivityPub (the same protocol used by Mastodon) to enable federation between instances:
- Announce — When a report is submitted, an
Announceactivity is sent to the vendor's inbox - Offer — Researchers can request access to reports on other instances
- Accept — Vendors can grant access by sending encrypted keys
- Disclose — Reports can be publicly disclosed, making them visible on the homepage
End-to-end encryption
All report content is encrypted using NaCl (libsodium):
- A symmetric key is generated for each report
- The content is encrypted with this key using XSalsa20-Poly1305
- The key is encrypted for each recipient using NaCl's
box(public-key authenticated encryption) - Only recipients with the corresponding private key can decrypt the key, then decrypt the content
This means the server operator cannot read any report content — only the researcher who submitted it and the vendor who has been granted access can decrypt it.
Authentication
Disclosure uses session-based authentication with HMAC-signed cookies. Passwords are stored as bcrypt hashes. There is no external OAuth — accounts are created via the CLI.
Rate limiting
Login and other sensitive endpoints are rate-limited per IP to prevent brute-force attacks.
CSRF protection
All state-changing requests require a CSRF token (double-submit cookie pattern) to prevent cross-site request forgery.
Security headers
The server sets standard security headers on every response:
X-Content-Type-Options: nosniffX-Frame-Options: DENYReferrer-Policy: strict-origin-when-cross-originContent-Security-Policywith strict defaultsPermissions-Policy: camera=(), microphone=(), geolocation=()