All projectsA closer look / 2026
Selected work / Case study

Sawtak

An anonymous whistleblowing platform built to make speaking up safer. Privacy at the network boundary, separate evidence paths, and tamper-evident records.

In depth / The technical documentation

Under the hood.

Explore the full technical details in the Sawtak documentation on Notion.

Read the technical docs
01 / Follow the request

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.

Sawtak / network mapIllustrated traffic · not a live service
An anonymous complaint travelling through SawtakAn illustrated flow, not live traffic. Browser to privacy proxy and its Redis session store, then the internal backend. Evidence is pinned to IPFS before its content ID is committed to the three-validator Proof of Authority testnet. Identified complaints instead use encrypted PostgreSQL data and private R2 evidence.Citizen’s browserPUBLIC / HTTPSsubmit →HTTPSPrivacy proxy:4000DMZ / Redis sessions + rate limitsRemove identifiers. Keep a session.No client IP forwarded or logged.Internal backend:8000BUN / ELYSIA.JS01 Verify proxy authentication02 Validate & filter the content03 Route by submission modePostgreSQL / Cosmos indexerSign transaction + evidence CIDIPFS / Pinataevidence in · content ID outPIN FIRST. THEN COMMIT THE CID.Identified onlyPostgreSQL / AES-256-GCMPrivate R2 evidence · no chainSawtaknode 01Sawtaknode 02Sawtaknode 03COSMOS SDK / PROOF OF AUTHORITY TESTNET✓ Illustrated block committed · proof of submissionAn anonymous complaint travelling through SawtakAn illustrated flow, not live traffic. Browser to privacy proxy and its Redis session store, then the internal backend. Evidence is pinned to IPFS before its content ID is committed to the three-validator Proof of Authority testnet. Identified complaints instead use encrypted PostgreSQL data and private R2 evidence.Citizen’s browserPUBLIC / HTTPSsubmit →encrypted in transitPrivacy proxy:4000DMZ / Redis sessions + rate limitsRemove identifiers. Keep a session.No client IP forwarded or logged.Internal backend:8000BUN / ELYSIA.JS01 Verify proxy authentication02 Validate & filter the content03 Route by submission modeIdentified only → encrypted Postgres + private R2IPFS / Pinataevidence in · content ID outPIN FIRST. THEN COMMIT THE CID.Sawtaknode 01Sawtaknode 02Sawtaknode 03COSMOS SDK / PROOF OF AUTHORITY TESTNET✓ Illustrated block committed · proof of submission
IPFS uploads happen before blockchain submission. Redis belongs to the privacy proxy, not the backend. The separate identified-report path keeps evidence in private R2 storage.
POST anonymous complaint → proxy:4000

01 / 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.

The request boundaryPublic → trusted
  1. Public internetBrowser · mobile · officials · OAuth

    External requests enter through one gateway.

  2. Privacy proxyDMZ / Elysia.js + Redis

    Anonymous sessions, rate limits, and identifying-header removal.

  3. Internal backendBun / Elysia.js + PostgreSQL

    Proxy auth, content validation, and mode-specific storage.

  4. Sawtak POA chainCosmos SDK / 3-validator testnet

    Anonymous records and evidence references, submitted by the backend.

Four application trust zones. Monitoring runs separately on the admin network; identified submissions do not go to the blockchain.

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.

01 / Anonymous

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.
02 / Identified

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.

The engineering takeaway

Privacy is not one encryption call.
It is what every layer chooses not to expose.

Architecture and test counts based on the Sawtak project README. The chain described here is a testnet.
02 / The layers, up close

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.

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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