Security

How we protect your test data

Nijam is a read-only reporting layer for Playwright, pytest, and Vitest. It ingests the results your CI already produces and never executes or re-runs your tests. Here's how we keep that data safe, end to end.

Last updated June 22, 2026

Encryption everywhere

All traffic runs over HTTPS/TLS. Passwords are hashed with argon2id, session and ingest tokens are stored only as SHA-256 hashes, and Slack tokens and two-factor secrets are encrypted with AES-256-GCM, never in plaintext.

Authentication & sessions

Email + password (argon2id), optional Google and GitHub sign-in, optional two-factor authentication (TOTP), and enterprise single sign-on (OIDC) for Pro organizations. Sessions live in HttpOnly, Secure, SameSite cookies and are revoked on logout, password change, and reset.

Split secret keys

CI uploads use write-only ingestion keys that can never read data, a leaked CI key exposes nothing. MCP/agent reads use separate read-only keys that can never write. Each key is shown once, stored as a SHA-256 hash, and revocable at any time.

Tenant isolation

Every project belongs to an organization. Requests are checked against your membership, and anything you can't access returns a plain 404, no resource enumeration.

Privacy-first telemetry

Error monitoring runs with PII disabled. Cookies, auth headers, and request bodies are stripped before they leave, and session replays mask all text and inputs.

Trusted infrastructure

Data lives on managed providers (Neon Postgres, Cloudflare R2) that encrypt at rest, and trace artifacts are served through short-lived, 15-minute signed URLs.

Bring your own cloud

Pro organizations can store their runs and artifacts in their own Postgres and their own S3, Google Cloud Storage, or Azure bucket. Your test data stays in your infrastructure; we keep only your account, organization, and billing.

Data encryption

Every connection to Nijam, the dashboard, the API, and the reporter, is served over HTTPS/TLS, and session cookies are marked Secure in production. Sensitive values are never stored in the clear:

  • Passwords are hashed with argon2id (never bcrypt, never plaintext).
  • Session, ingest, email-verification, and password-reset tokens are stored only as SHA-256 hashes, the raw token exists only in your browser cookie or the one-time key you copy.
  • Slack bot tokens, SSO client secrets, and bring-your-own-cloud connection strings and credentials are encrypted at rest with AES-256-GCM and are never returned to clients or written to logs.
  • Our managed database (Neon Postgres) and object storage (Cloudflare R2) encrypt data at rest.

Authentication & account security

You can sign in with email and password or with Google or GitHub. We took care to make accounts hard to attack and hard to enumerate:

  • Login returns the same error for an unknown email and a wrong password, and equalizes timing so it can’t be used to discover which emails have accounts.
  • Email verification and password-reset links are single-use and time-limited (24 hours and 1 hour respectively); a password reset signs you out of every session.
  • Google and GitHub sign-in use an HMAC-signed, short-lived state parameter to prevent CSRF, and only match accounts on a verified email address.
  • Optional two-factor authentication (TOTP) adds an authenticator-app code to sign-in; the shared secret is encrypted at rest (AES-256-GCM) and one-time backup codes are stored only as SHA-256 hashes.
  • Pro organizations can require enterprise single sign-on (OIDC) through their own identity provider (Okta, Entra ID, Auth0, and others). Each connection is per-organization and uses the Authorization Code flow with PKCE; the client secret is encrypted at rest (AES-256-GCM); and SSO only routes a login once the organization has proven ownership of the email domain with a DNS TXT record. Admins can enforce SSO so password and social sign-in are blocked for their domains.
  • Sessions are stored server-side, expire after 30 days, and are revoked on logout and on any password change.

API access & ingest keys

Secret keys come in two strictly separated kinds. Ingestion keys (nij_sk_…) are what your CI uses as a bearer token , they can submit runs, results, and artifacts but can never read your data, so the key most exposed to leaks (the one in CI config) unlocks nothing. Read keys (nij_rk_…) power the Nijam MCP server and other read integrations, they can read test data within their scope but can never write. Neither kind can change settings, manage members, or touch billing. Each key is scoped to a single organization or project, shown in full exactly once at creation, stored only as a SHA-256 hash, and can be revoked at any time.

Third-party integrations

Integrations are opt-in, connected by an organization admin through an HMAC-signed flow, and can be disconnected at any time. We hold as little as possible to make each one work:

  • GitHub, the Nijam GitHub App posts a status check and a single sticky comment on the pull request for a run. We store no GitHub token: access uses short-lived installation tokens minted on demand and signed by the App’s private key, and the App holds only the permissions it needs, writing commit checks and pull-request comments. It never reads your source code.
  • Slack, posts run notifications to the channel you choose. The bot token is encrypted at rest with AES-256-GCM and is never returned to clients or written to logs.
  • MCP / AI agents, a read-only nij_rk_… key lets an MCP client query your runs. The server runs locally as a subprocess of your client, so the key stays on your machine and we only ever see the read requests it makes. What an agent then does with the data it retrieves is governed by that agent and its model provider, both of which you choose.

Access control & tenant isolation

Projects belong to organizations, and every read is scoped to your membership in that organization. If you request something you’re not a member of, you get a plain 404 rather than a “forbidden”, so the API never reveals whether a resource exists. Sensitive organization actions (members, billing, settings) are additionally gated to organization admins.

Abuse protection & input validation

Public and authentication endpoints are hardened against abuse:

  • Rate limiting on signup, login, verification resend, and password-reset requests.
  • Every request body and parameter is validated against a strict schema before it reaches any handler.
  • Cross-origin requests are restricted to our own web app.

Monitoring & data minimization

We use error monitoring only to keep the service reliable, and we minimize what it ever sees. Telemetry is disabled unless explicitly configured; when it runs, personal data collection is off, and cookies, authorization headers, and request bodies are stripped before anything is sent. On the web, error session replays mask all text and inputs. The browser never stores your test data, only a session cookie (set by the API) and your theme preference.

Bring your own cloud (Pro)

Pro organizations can keep their test data entirely in their own infrastructure. With bring your own cloud enabled, your projects, runs, and artifacts are stored in your Postgres database and your object storage (AWS S3 or any S3-compatible store, Google Cloud Storage, or Azure Blob Storage). We keep only your account, organization, membership, and billing.

  • The connection string and cloud credentials you provide are encrypted at rest with AES-256-GCM and are never returned to clients or written to logs.
  • We only accept a database or storage endpoint reachable at a public address, requests to private, loopback, and link-local targets (including cloud metadata endpoints) are rejected.
  • You grant the least privilege that works: a database role scoped to its own schema, and storage credentials scoped to a single bucket.
  • Disabling it reverts new data to our managed cloud and leaves the data already in your cloud untouched, it is yours.

Infrastructure & sub-processors

Nijam runs on established managed providers, each responsible for the security of their own platform. We use:

  • Neon, managed Postgres database.
  • Cloudflare R2, object storage for traces, screenshots, and videos.
  • Vercel, hosting for the web app; Railway, hosting for the API.
  • Resend, transactional email (verification and password-reset messages).
  • Better Stack, error monitoring (PII disabled); Polar, billing and payments.
  • Slack and the Nijam GitHub App, only for the integrations you connect; Google/GitHub for the sign-in methods you use; and your own identity provider (e.g. Okta) for SSO, if you configure it.

Your data & ownership

Your test results are yours. Nijam is a read-only layer that stores the runs, test outcomes, timings, and artifacts your CI sends us, it never executes or re-runs your tests. Deleting a project removes its runs, results, and artifacts. For details on what we collect and why, see our Privacy Policy.

Compliance

We want to be straight with you: Nijam is an independent, early-stage product and we do not currently hold formal certifications such as SOC 2 or ISO 27001. What we do have is the set of engineering practices described on this page, built on top of infrastructure providers that maintain their own security and compliance programs. If your organization needs specific security documentation, reach out and we’ll do our best to help.

Reporting a vulnerability

If you believe you’ve found a security issue, please email support@nijam.dev with the details and steps to reproduce. We’ll acknowledge your report, investigate, and keep you updated. Please give us a reasonable chance to fix the issue before disclosing it publicly.

Bring your test results somewhere safe

Point your CI at Nijam and turn the results you already produce into flakiness detection and failure analytics, no agents, no re-runs.

Free while you connect your first project · works with GitHub Actions, Jenkins, GitLab CI & CircleCI