Security.
What we actually do to protect your account and your data — and, just as importantly, what we haven’t built yet. No blanket compliance claims, no invented certifications.
Authentication & sessions
Passwords are hashed with bcrypt (cost factor 12) — we never store them in plain text. Sessions use a random 32-byte token; only its SHA-256 hash is stored in the database, so a database read alone can’t be used to forge a session. Session cookies are httpOnly and sameSite=lax, and secure once served over HTTPS.
View in engineering documentation (docs/SECURITY.md) →Access control & tenant isolation
Five roles (Owner/Admin/Manager/Editor/Viewer) map to a fixed permission set checked on every mutating request — never an inline role-name comparison. Every organization-scoped request is re-verified against real membership in the database before it can touch that organization’s data.
View in engineering documentation (docs/SECURITY.md) →OAuth token storage
Access and refresh tokens for connected social accounts are encrypted at rest with AES-256-GCM before they touch the database, using a key that is never hard-coded or logged. Tokens are only decrypted server-side, immediately before a call to the relevant platform, and never appear in an API response.
View in engineering documentation (docs/SECURITY.md) →OAuth connect flow
Connecting a platform uses a single-use, time-boxed CSRF state value and PKCE where the platform supports it. Disconnecting revokes the token with the platform directly for the platforms that offer a real revocation endpoint (Facebook, Instagram, X, YouTube); for the other four, we say so plainly rather than claim a revocation that didn’t happen.
View in engineering documentation (docs/OAUTH_PRODUCTION_SECURITY.md) →Input validation & injection protection
Every mutating endpoint validates its request body against a schema before it reaches the database. All database access goes through a parameterized query layer — there is no string-concatenated SQL anywhere in the codebase. All UI rendering goes through React’s default escaping.
View in engineering documentation (docs/SECURITY.md) →Rate limiting
Login, registration, OAuth connect, publishing, media upload, AI generation and inbound webhook endpoints are all rate-limited. Password-reset requests are limited per email address specifically, so an attacker with many IP addresses can’t email-bomb one account.
View in engineering documentation (docs/SECURITY.md) →Webhook verification
Inbound webhooks from the Meta platform family (Facebook, Instagram, Threads) are verified with HMAC-SHA256 signatures before being processed. Platforms we haven’t implemented signature verification for are rejected outright at the route level rather than processed unverified.
View in engineering documentation (docs/SECURITY.md) →What we haven’t built yet
Disclosed here rather than left for you to discover, and tracked in the same engineering documentation as everything else on this page.
- No multi-factor authentication yet.
- CSRF protection relies on SameSite=Lax cookies plus JSON/header requirements, not a dedicated CSRF token.
- Content-Security-Policy currently allows ‘unsafe-inline’ for scripts and styles (a nonce-based CSP is a planned follow-up).
- Webhook signature verification is implemented for the Meta platform family only.
- Uploaded media is validated by MIME type and re-encoded on the image path, but not scanned for malware.
TLS is terminated at the hosting platform’s edge rather than inside the application itself — standard practice for the platforms NUA Social deploys to, and how the secure cookie flag is able to activate correctly in production.
Reporting a vulnerability
A dedicated security-disclosure contact isn’t set up yet. Once one exists, it will be linked from this page rather than asserted before it’s real.