Sawtak
An anonymous whistleblowing platform built to make speaking up safer. Privacy at the network boundary, separate evidence paths, and tamper-evident records.
Under the hood.
Explore the full technical details in the Sawtak documentation on Notion.
A voice travels.
The metadata doesn’t have to.
One anonymous complaint, from the first click to a tamper-evident record. Here’s what each boundary leaves behind.
POST anonymous complaint → proxy:400001 / 08Submit over HTTPS
A walkthrough of the anonymous path. The identified path stays private, editable, and off-chain. Content addressing is not encryption.
How do you make
speaking up safer?
Sawtak is an anonymous whistleblowing platform for reporting misconduct and corruption. Built as a graduation project at Ain Shams University, it treats privacy as an architectural constraint: separate identity from the reporting pipeline, keep evidence on the right storage path, and make submitted records tamper-evident.
- Trust zones
- 04
- Submission modes
- 02
- Testnet validators
- 03
Privacy starts at the boundary.
The privacy proxy is the only public entry point to the API. The backend lives on an internal network and verifies proxy authentication before handling a request. Redis stays with the proxy; PostgreSQL stays with the backend.
-
Public internetBrowser · mobile · officials · OAuth
External requests enter through one gateway.
-
Privacy proxyDMZ / Elysia.js + Redis
Anonymous sessions, rate limits, and identifying-header removal.
-
Internal backendBun / Elysia.js + PostgreSQL
Proxy auth, content validation, and mode-specific storage.
-
Sawtak POA chainCosmos SDK / 3-validator testnet
Anonymous records and evidence references, submitted by the backend.
Less information crosses the boundary.
The proxy removes client-IP headers such as x-forwarded-for, x-real-ip, and cf-connecting-ip. It replaces the browser’s User-Agent, removes the referrer and non-session cookies, and forwards a proxy session identifier instead. The design avoids IP logging at both proxy and backend layers.
Redis handles anonymous sessions and sliding-window rate limits at the edge. The internal API checks X-Proxy-Secret, applies authentication where needed, and runs Gemini-based spam and content validation before writing to a database or chain.
Two modes. Two evidence paths.
An anonymous report and an identified complaint have different privacy and editing requirements. They deliberately do not share the same persistence pipeline.
A record that stays.
IPFS / Pinata → Cosmos
- Evidence is uploaded to IPFS through Pinata first.
- The returned content identifier (CID) is committed with the complaint on-chain, under a public pseudonym.
- A Cosmos indexer mirrors chain events into PostgreSQL for querying.
- Committed complaints are not editable. Signed proofs of submission and hashed tracking codes support follow-up.
A private, editable record.
PostgreSQL + private R2
- Complaint data is encrypted with AES-256-GCM in PostgreSQL.
- Evidence stays in private Cloudflare R2 storage.
- Identified evidence never goes to IPFS or the blockchain.
- Records remain editable, with identity access restricted to the administrative workflow.
Proof, without a token economy.
Sawtak uses a custom Cosmos SDK chain with Proof of Authority rather than public Proof of Stake. Only pre-approved validators produce blocks. The standard staking and minting modules are disabled in favour of a custom poa module, so there is no public staking, inflation, or validator token reward scheme.
The development testnet runs three validators. Anonymous complaints carry cryptographic proofs of submission, while evidence CIDs preserve a tamper-evident reference without putting large files on-chain.
This makes the trust assumption explicit: record integrity depends on the approved authority set. It is not a claim of permissionless governance or absolute censorship resistance.
Small services. Clear responsibilities.
- Frontend
- Next.js 16, TypeScript, React Query, Zustand
- Backend & proxy
- Bun and Elysia.js, with a separate privacy-proxy service
- Data & queues
- PostgreSQL 15, Prisma ORM, Redis, Bull
- Blockchain
- Cosmos SDK, a custom POA module, and CosmJS
- Evidence
- IPFS / Pinata for anonymous reports; private Cloudflare R2 for identified complaints
- Identity & access
- Google OAuth, Haweya national-ID OAuth, JWT access and refresh tokens, team-based RBAC
- Observability
- Prometheus, Grafana, Redis and PostgreSQL exporters, Alertmanager
Docker or Podman Compose brings the services and three-node testnet up together, with configuration supplied through an environment file. A mock Haweya OAuth provider supports local development.
Built to be checked.
The project’s documented test suite separates isolated route behaviour from the real request pipeline.
- Unit / route-layer tests
- 184
Mocked dependencies and inline Elysia handlers. No network required.
- Integration tests
- 24
A live proxy-to-backend pipeline against PostgreSQL and Redis.
Watch the boundaries, not just uptime.
Prometheus collects request rates, latency, errors, stripped-header counts, and rate-limit activity. Redis and PostgreSQL exporters add storage and connection health; Grafana brings the signals together in pre-provisioned dashboards.
Alertmanager routes email or webhook notifications for conditions including an unreachable backend, elevated 5xx rates, high p95 latency, and database or cache pressure. Monitoring stays on the admin network.
Accountability on the other side of anonymity.
Administrative actions are audited. Identity reveal requires two-step approval, from Team Admin to Platform Admin. Passwords use bcrypt with cost 12; JWT access and refresh tokens and role-based permissions control authenticated workflows.
Privacy is not one encryption call.
It is what every layer chooses not to expose.
Privacy isn’t a switch.
It’s a sequence of decisions.
From the submission interface to the review desk. Each layer has a job, and a boundary it shouldn’t cross.
- Submission & the privacy boundary
Start with a voice.
A report arrives over HTTPS. The privacy proxy removes identifying headers, replaces the browser’s User-Agent, and uses an anonymous session to carry the request onward.
- HTTPS
- Metadata stripping
- Redis sessions
- Authentication & validation
Check it. Protect it.
The internal backend verifies the proxy, checks access, and filters invalid content before persistence. Identified complaint data is encrypted with AES-256-GCM; its evidence stays private in R2.
- Proxy authentication
- Content filtering
- AES-256-GCM
- Anonymous evidence / IPFS
Evidence comes first.
Anonymous evidence is pinned through IPFS / Pinata before a transaction is created. Its content identifier comes back to the backend, ready to become a tamper-evident reference.
- IPFS / Pinata
- Content addressing
- CID returned first
- The authority ledger
Make the record last.
The backend signs and submits the anonymous complaint with its evidence CID to the custom Cosmos POA chain. Three approved testnet validators maintain the ledger; a signed proof supports tracking.
- Cosmos SDK
- Proof of Authority
- Proof of submission
- Review & administration
Keep the follow-up accountable.
Officials review reports through role-based dashboards, with admin actions recorded in an audit trail. Revealing an identity requires two approvals: Team Admin, then Platform Admin.
- Role-based access
- Two-step approval
- Audit trails