Security
Last updated:
This page describes the security posture of Argus today. It deliberately avoids marketing language — if a control isn't in place, we don't list it.
Encryption
- In transit: TLS 1.2+ everywhere. The dashboard, API, and Stripe webhook ingress are HTTPS-only; HTTP requests redirect.
- At rest: Postgres storage on Render is encrypted at the volume level. Application secrets (JWT signing key, Stripe secret, Resend API key) are kept as Render environment-variable group values, not in code.
- Passwords: bcrypt hashed at cost factor 12. Plaintext never reaches the database.
Tenant isolation
- Every tenant-scoped table has PostgreSQL Row-Level Securitypolicies (
backend/db/rls-policies.sql). The application runs as a Postgres role withoutBYPASSRLS, so even a query that forgets aWHERE org_id = $1filter is rejected by the database. - Each request runs inside a transaction with
app.current_org_idandapp.current_user_idset viaSET LOCAL; the values are gone the moment the transaction commits. Connection reuse across tenants is therefore safe. - Migrations and ad-hoc admin scripts run as a separate Postgres role with BYPASSRLS — that role is never used by the running application.
Authentication
- Email + password sign-up with verified email. Refresh + access tokens are issued as HttpOnly + Secure + SameSite=Lax cookies; the access token is short-lived (15 min) and the refresh token is server-side revocable (
auth_sessionstable). - Brute-force protection via constant-time bcrypt against a sentinel hash on unknown emails (no user-enumeration timing channel).
- Per-IP rate limit on every
/api/*path (200 requests / 15 min). Per-tenant + per-API-key buckets are planned (Phase 5+). - MFA (TOTP) is on the roadmap for Pro+ plans; required for owners and admins on Team+ plans.
Audit log
Every state-changing action emits a row in audit_logs with the actor (user or API key), the action verb, the resource, IP address, and user-agent (truncated at 500 chars). Visible to org owners and admins under /[orgSlug]/audit-log. Retention by plan tier (see privacy policy §6).
API keys
- Issued at the project level (not user level). Stored as SHA-256 hashes; the plaintext is shown exactly once at create time.
- Permission-scoped (e.g.
sessions:write). Rotation tracked via arotated_from_idchain so a compromised key's history is inspectable.
Webhooks
Outbound webhooks are HMAC-SHA256 signed with a per-endpoint secret on a Stripe-style header (Argus-Signature: t=<ts>,v1=<hex>). The timestamp is the consumer's replay-protection mechanism — verify it's within 5 minutes before trusting the signature. Secrets are returned exactly once at creation; rotation is one-click in the dashboard.
Logging
- Pino structured JSON logs with field-level redaction. Patterns scrubbed at write time include
password,passwordHash,token,refreshToken,authorization,cookie,set-cookie— top-level and on nested fields. - Request-id propagation: every log line for a request is joinable on
req.id(echoed back as thex-request-idresponse header). - Health-probe traffic (
/api/healthz,/api/readyz) is filtered out of the access log to keep signal up.
Backups
Render Postgres ships daily backups with 7-day retention on Starter, 30 days + point-in-time recovery on Pro. We restore-test once per quarter.
Incident response
Personal-data incidents are reportable to affected customers within 72 hours of confirmation per GDPR Article 33. The response runbook lives in docs/security/incident-response.md (internal). Contact path for outsider reports of vulnerabilities: support@argus-profiler.com — we coordinate disclosure under standard responsible-disclosure terms.
What we don't have yet
Honest list of in-flight controls:
- SOC 2 Type II — designing toward it (audit logs, access controls, incident response are all in place); auditor engagement is a separate workstream that requires customer demand.
- A bug-bounty program — happy to receive coordinated disclosure via the email above; no monetary bounty until we have the volume to run a structured program.
- SAML / SSO — Phase 5+ deliverable.