Security & privacy

Your messages are not ours to read.

TradesMen Messenger is engineered so the operator (us) cannot read your private content. Private keys live on your device. Sensitive admin actions are written to immutable audit logs. Where we still have work to do before public release, we say so directly on this page — no marketing.

What the server cannot read

  • Plaintext message bodies
  • Plaintext media — photos, videos, files, voice notes
  • Voice and video call payloads
  • Your private encryption keys
  • Contact-invite raw tokens (only HMAC'd hashes are stored)

What metadata we do see

  • Account identifiers and your chosen handle
  • Public encryption keys and signed pre-keys
  • Conversation membership and high-level metadata (size, timestamps, participants)
  • Encrypted message records — ciphertext only, with envelope headers
  • Reports you choose to send and the reason you submit
  • Account email and (optional) phone for recovery, never exposed to other users
Data classification

Who can see what.

A clear matrix of every data class the platform handles, where it lives, and who can read it. Nothing in this table is hidden by marketing language; if a row reads "operator" that means us, and we list how it's gated.

Data class Where it lives You Recipients Operator
Message body (text, reactions, edits) Encrypted on device; ciphertext on server Yes Yes No — never decryptable server-side
Attachments & voice notes Encrypted on device; opaque ciphertext blob in object storage Yes Yes No — server holds the blob, not the key
Call media (audio & video) DTLS-SRTP between participants; relayed via TURN if needed Yes Yes No — TURN relays ciphertext only
Private encryption keys Device only — iOS Keychain or Android Keystore Yes (via biometric unlock) No No — never leaves the device
Public keys & signed pre-keys Server (for delivery routing) Yes Yes Yes — public material only, by design
Account email (recovery) Server Yes No — never surfaced SuperAdmin only, gated by audited operations
Account phone (optional recovery) Server Yes No — never surfaced SuperAdmin only, gated by audited operations
Handle & display name Server Yes Yes (when added as a contact) Yes
Conversation membership / timestamps Server (delivery metadata) Yes Yes (own threads) Yes — minimised but unavoidable for delivery
Reports you submit Server Yes No SuperAdmin reveal flow — written reason + audit log required
Push tokens Server (forwarded to APNs/FCM) Yes — payload itself is privacy-safe
Contact-invite raw tokens Returned once at creation; never stored Yes (until consumed) Receiver (until consumed) No — only HMAC'd hash is persisted
Audit logs (admin actions) Server (append-only) No No SuperAdmin read; never overwritten
Threat model

What we're defending against — and what we're not.

A clear threat model is more useful than vague claims. Here's the shape of what TradesMen Messenger protects against today, and where the limits are.

What we defend against

  • An attacker who compromises the server reading historical messages — ciphertext only.
  • An attacker who compromises the server reading historical media — opaque blobs only.
  • An attacker observing TLS traffic — everything is on TLS 1.2+.
  • An attacker stealing a backup of the database — keys are not in the database.
  • A casual operator reading reports — reveal flow requires a written reason and is logged.
  • Phishing of the web product — there is no public web user login to phish.
  • Push payload leakage — pushes never include sender, recipient, or content.

Out of scope today

  • An attacker with full physical control of an unlocked, biometric-bypassed device.
  • A targeted attack against an installed app combined with OS-level compromise.
  • A motivated attacker correlating who-talks-to-whom across a sufficiently long window — we minimise metadata but not zero it.
  • Production-grade end-to-end encryption guarantees on the public store builds — the current builds use a placeholder crypto module gated against release.
Cryptographic primitives

The algorithms, not just the buzzwords.

Every "encrypted" line elsewhere on this site maps to one of the rows below. If you're auditing the platform this is the table to start from.

Use Primitive Key / parameter Notes
Message body / attachment encryption AES-GCM 256-bit content key, 96-bit nonce, 128-bit tag Per-message / per-file content key. Wrapped inside the E2EE envelope to recipients.
Identity & signed pre-keys X25519 (DH) + Ed25519 (sign) Curve25519 (256-bit) Per-device. Signed pre-keys carry a fresh signature on every rotation.
Symmetric session ratchet HKDF + AES-GCM HKDF-SHA-256 → 256-bit AES keys Forward secrecy on each chain step; placeholder today, vetted Signal/MLS-compatible build before public store releases.
Group epoch state HKDF-derived sender keys 256-bit per-epoch key Member-aware: epochs roll on join/leave so old members can't read new content and new members can't read old.
TLS in transit TLS 1.2+ (ECDHE) P-256 / X25519 + AES-GCM or ChaCha20-Poly1305 HSTS enabled in production. We never accept plaintext or downgraded ciphersuites.
Call media path DTLS-SRTP AES-128/256 + HMAC-SHA-1/256 per WebRTC profile End-to-end between participants. TURN relays the ciphertext only.
Password storage at rest Argon2id Server-tuned memory / iterations Per-user salt. Resilient to GPU brute-force.
JWT (access tokens) HMAC-SHA-256 (HS256) ≥ 32-byte secret (validated at boot) Strict iss, aud, typ checks. 15-minute access TTL, 30-day refresh TTL.
Contact-invite tokens HMAC-SHA-256 ≥ 32-byte server-side secret Server stores only the HMAC'd hash. Plaintext is returned exactly once at creation.
Local-storage at rest (mobile) iOS Keychain / Android Keystore Hardware-backed where available Biometric-unlocked. Secure Enclave on iOS; StrongBox on supported Android.
Cryptographic randomness OS CSPRNG random_bytes / SecRandomCopyBytes / SecureRandom Never rand / Math.random. Verified by static checks on every change.
Crypto details

Device keys, identity, and key change handling.

Per-device key bundles

Each device publishes its own identity key, signed pre-key, and a set of one-time pre-keys. Adding a new device generates a new bundle — your existing devices are not impersonated and cannot be silently replaced.

Safety numbers & key change alerts

Conversations track the public-key fingerprint of the other side. If a peer's key changes — for example after a reinstall or a new device — the app surfaces a key-change banner before it sends the next message, so you can verify before you talk.

Group key handling

Group conversations use member-aware keys with a wrapped epoch state. When members join or leave, keys roll forward without exposing previous content to new members or future content to former members.

Encrypted media uploads

Attachments are encrypted on-device with a per-file content key. The key is delivered inside the E2EE message; the upload itself is opaque ciphertext. No thumbnails, no previews, no scanning on our side.

Calling

WebRTC voice and video, with privacy on the wire and in the push.

Encrypted media path

All call media is DTLS-SRTP encrypted between participants. The signalling channel is our authenticated WebSocket. Calls are peer-to-peer where possible; relayed via our coturn server when networks block direct connections.

Short-lived TURN credentials

STUN/TURN credentials are short-lived and bound to the call session. A leaked credential cannot be replayed against an unrelated call later.

Privacy-aware call pushes

Incoming-call pushes include only what's needed to wake the app. Caller identity, recipient identity, and call topic are never embedded in the push payload.

WebRTC handler validation

Server-side WebRTC handler validates call membership for both sender and target on every signalling message, and checks the call is live — preventing replay or off-call signalling abuse.

Admin discipline

Operating the service without operating on your data.

A real product needs an operator. The point isn't to pretend nobody runs the service — it's to make sure that running it cannot quietly turn into reading your messages.

SuperAdmin-only console

The admin panel is gated by the SuperAdmin role, an IP allowlist, optional TOTP, and CSRF on every state-changing route. There is no public web user login; ordinary users access the service from the iOS or Android app only.

Audited reveals & bans

Reading reported plaintext, banning a user, exporting a profile, or editing legal documents writes a record into admin_audit_logs with the actor, IP, reason, and timestamp. Reveal flows require a written reason — the panel won't let an admin read content casually.

Privacy-safe reporting

When you report a user or a message from inside the app, you choose what to share. Reports include only the metadata you opt into. The server cannot decrypt reported content without the explicit, audited reveal step.

Force-logout & ban propagation

Bans and force-logouts propagate to every device on the next request. New session refreshes are denied; existing tokens are revoked through a SystemEventService broadcast, not just a UI toggle.

Operational security

The boring stuff that actually matters.

Rate limiting and abuse controls

Rate limits on auth, contact-invite, and reporting endpoints. Rotating tokens, signed JWTs with strict issuer/audience/typ validation, and revocation paths for compromised devices.

Environment validation at boot

The backend refuses to boot in production with insecure defaults. Required env keys (JWT secret, CORS origins, trusted proxies, contact-invite secret + base URL, push provider settings, E2EE mode) are validated up-front.

Static checks on every change

A static-check runner enforces 90+ privacy invariants on every change — no plaintext columns on the messages table, no plaintext logging, no /api/api routing mistakes, no placeholder-crypto leaks past the production gate, no force-uppercased invite tokens, deep-link manifest sanity, etc.

Retention and deletion

Per-data-class retention policies are enforced by background workers. Account deletion runs on a 7-day grace window before anonymization. Failed jobs surface in the admin dashboard.

Supply chain

Dependencies are pinned with lockfiles and reviewed on update. The mobile apps ship no third-party analytics or ad SDKs. Production push providers (APNs, FCM) are configured via env, not vendored libraries.

Backups

Encrypted database backups; key material is stored separately from data backups so a stolen backup cannot be decrypted in isolation. Backup restore drills are part of the operational checklist.

Compliance posture

Where we map to common privacy frameworks.

We're not yet certified against any specific framework. We do build the platform to map cleanly to the principles below — and we're honest about the gap between "designed to" and "audited against."

PIPEDA & PIPA (Canada)

  • Accountability: Pimentel Services Ltd. is the operator and contact of record.
  • Limiting collection: No phone or email search; no contact-list scraping; no analytics SDKs.
  • Limiting use, disclosure, and retention: Per-data-class retention with worker-driven aging; account deletion in seven days.
  • Safeguards: E2EE for content, ciphertext-only at rest, audited admin actions.
  • Individual access: In-app data export and deletion; written request via /user-data-request.

GDPR (EEA / UK)

  • Lawful basis: Contractual necessity for service delivery; consent for optional phone verification.
  • Data minimisation: Server stores ciphertext + minimum routing metadata.
  • Storage limitation: Configurable retention; default 7-day grace then anonymization.
  • Right to access / erasure / portability: In-app export and deletion; written DSAR via privacy contact.
  • Data protection by design: Privacy invariants enforced by static checks before merge.
  • International transfers: Hosting region documented in the company-tier DPA.

NIST CSF alignment

  • Identify: Data classes, owners, and retention policies are documented above.
  • Protect: E2EE, biometric local-storage, environment validation, MFA on admin, rate limits.
  • Detect: Live status board, immutable audit logs, breach-incident tracking.
  • Respond: Documented in /breach-response; on-call paged through internal alerting.
  • Recover: Encrypted backups; backup-restore drills; revocable tokens and force-logout.

Industry-aligned data handling

  • OSHA / WSIB-style record retention: retention windows configurable on the company tier so safety briefings + incident reports stick around as long as your jurisdiction requires.
  • Construction lien / records of work: exports include conversation membership and timestamps; ciphertext bodies live with the device that holds the keys.
  • Insurance / claims discovery: SuperAdmin reveal exists for audited legal-process responses, with written reason and immutable audit log.

Compliance certification (ISO 27001, SOC 2 Type II) is on our roadmap but not yet completed. We don't claim a status we haven't earned. Email privacy@example.com if you need our current attestation package.

Where we still have work to do

We don't claim production-grade end-to-end encryption today. The current native builds ship with a placeholder crypto module that's gated against release builds — it cannot be enabled in production unless the production gate is satisfied. Public app-store releases will require a vetted Signal/MLS-compatible crypto module before they ship. The backend is already designed for ciphertext-only storage. For implementation status see E2EE_IMPLEMENTATION_STATUS.md in the repository.

Reporting a security issue

Email security@example.com. Please include reproduction steps, impact, and a way to contact you. We acknowledge reports promptly and will keep you informed through remediation. Coordinated disclosure is welcomed — let us know what timeline you have in mind and we'll work to it.

For privacy questions or data subject requests: privacy@example.com. For everything else: support@example.com.