Pentestas / help

Per-Tenant Encryption and BYOK: How Pentestas Handles Your Sensitive Findings

Per-Tenant Encryption and BYOK: How Pentestas Handles Your Sensitive Findings

Master key Production env secret Tenant A Fernet key wrapped by master Tenant B Fernet key wrapped by master Tenant C Fernet key wrapped by customer KMS BYOK (Enterprise) Finding evidence • Request bodies • Response snippets • Payload strings • AI narrative • AI impact • Remediation hints All Fernet-encrypted
One master key. One Fernet key per tenant. BYOK swap on Enterprise. No cross-tenant decryption.

Every AI pentest finding carries evidence: full HTTP request + response, payloads used, response bodies, AI-written narratives that sometimes reference secrets the finding exfilled. This is data you do not want visible to anyone — including Pentestas staff — beyond the tenant that owns the scan.

This post is the engineering-level answer to "how exactly do you handle our data" — the question every InfoSec team asks before they'll sign the MSA.

The data-sensitivity model

A Pentestas scan produces multiple data classes, each handled differently:

Class Sensitivity At-rest protection
Target URL Low Not encrypted (needed for dashboard search)
Scan config Medium Fernet-encrypted with tenant key (secrets stripped pre-persist)
Finding title / severity / CVSS Low Not encrypted (needed for dashboard filter)
Finding evidence (request + response) High Fernet-encrypted with tenant key
AI narrative / impact / remediation High Fernet-encrypted with tenant key
Payload used High Fernet-encrypted with tenant key
Stored credentials (Azure SP secret, GWS SA key, target passwords) Critical Fernet-encrypted with tenant key — never returned in API responses
Anthropic API key (BYOK) Critical Fernet-encrypted with master key

How the key hierarchy works

Master key

  • Stored as the MASTER_ENCRYPTION_KEY env var in the production environment.
  • Rotated annually on the major-release schedule.
  • Never logged. Never returned from any API. Never written to disk outside the environment secret store.

Tenant Fernet keys

  • Generated on first use per tenant.
  • Stored in the tenants.encryption_key column — encrypted with the master key before DB persist.
  • Used to encrypt sensitive fields on every scan row before insert.
  • Decrypted in-process per-request; plaintext never leaves the worker's memory.

Per-field encryption

  • Implementation in app/encryption/fields.py.
  • Every sensitive finding column goes through encrypt_field(fernet, plaintext) on insert + decrypt_field(fernet, ciphertext) on read.
  • The Fernet format (AES-128-CBC + HMAC-SHA256 in one token) protects against both tampering and passive snooping.

BYOK — bring your own key

Enterprise customers can supply their own KMS root:

  • AWS KMS — ARN-based reference to a customer CMK.
  • Azure Key Vault — vault URI + access policy or RBAC role.
  • GCP Cloud KMS — resource path + SA binding.

With BYOK, the tenant's Fernet key is wrapped by your KMS, not Pentestas's master. Revoking your KMS grant immediately denies Pentestas's infrastructure access to your findings. Pentestas staff with DB access see only ciphertext.

Key rotation

When a tenant key rotates:

  1. New Fernet key generated (or minted via KMS for BYOK).
  2. Background task re-encrypts every row for that tenant.
  3. Old key retained for 7 days (defence against rotation mistakes).
  4. After 7 days, old key is zeroised.

Rotation can be triggered on-demand by an admin or on a schedule (Enterprise).

Cross-tenant isolation

Beyond encryption, tenant isolation is enforced at three layers:

Application layer

Every authenticated request sets tenant_id context from the JWT / API key. Every DB query filters WHERE tenant_id = :tid. No authenticated request ever sees another tenant's rows.

DB layer — PostgreSQL Row-Level Security

Every tenant-scoped table has RLS enabled + forced:

sql
ALTER TABLE scans ENABLE ROW LEVEL SECURITY;
ALTER TABLE scans FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON scans
  FOR ALL
  USING (tenant_id = current_tenant_id())
  WITH CHECK (tenant_id = current_tenant_id());

The application's DB user is subject to RLS. Even if the application has a SQL-injection bug, queries against the pentestas_app user see zero rows when the tenant context isn't set. Forced RLS means the policy applies to the table owner too, not just regular users — so a SUPERUSER bug wouldn't let you bypass it.

Backup layer

DB backups are per-tenant split — a backup of tenant A cannot be restored in a location with tenant B's encryption key, because the key material doesn't export cleanly across infrastructures. Full cross-region restore requires explicit BYOK key-wrapping re-negotiation.

In transit

  • Public API + web UI — TLS 1.3 (TLS 1.2 accepted for legacy clients, disabled for Enterprise tenants on request). HSTS preload. OCSP stapling.
  • Internal services (web ↔ DB, web ↔ Redis, worker ↔ anthropic) — internal Docker network, not exposed externally. Anthropic traffic egresses on TLS 1.3.
  • Agent ↔ platform — WebSocket over TLS 1.2+. Strict cert pinning to *.pentestas.com — agents refuse connections that don't match.

Credential handling

Target credentials (paths to the system under test)

  • Stored in scan.config JSONB temporarily.
  • Passed to the Celery worker as part of the task message.
  • Not persisted to the DB after the worker starts. The config column is rewritten post-scan to remove target_username, target_password, cookies, custom_headers, and oauth_refresh fields.
  • Rescans must re-supply credentials (via RescanRequest body) because they're genuinely not saved.

Azure / GWS / cloud credentials

  • Stored encrypted per-tenant in tenants.azure_credentials_enc + similar columns.
  • Decrypted in-process per scan.
  • Never returned in API responses beyond "configured: yes / no" + credential type.

Anthropic API keys (BYOK)

  • Stored encrypted with the master key (not the tenant key) in tenants.anthropic_api_key_enc.
  • Decrypted in-worker only during AI analysis.
  • Never logged, never returned.

Data retention

Plan Scan + finding retention Backup retention
Free 365 days 30 days
Pro 3 years 90 days
Enterprise Unlimited (customer-configurable) 7 years (customer-configurable)

Retention boundaries auto-purge expired scans. Purges cascade: delete scan → delete findings, reports, attack chains, agent dispatch records.

For regulated entities with specific retention obligations (PCI, HIPAA's 6-year recommendation, SEC 17a-4 for financial records, etc.), Enterprise retention is configurable per data class.

Audit logging

Every security-relevant action writes an audit row:

  • Login + failed-login attempts (with IP + UA).
  • Role change / user invitation / user removal.
  • API-key create / revoke.
  • Scan create / cancel / delete.
  • Agent create / disable / delete.
  • Settings changes (including credential updates).
  • CIS benchmark run, Azure scan dispatch, scheduled-scan modification.

Retention: 365 days on Pro, unlimited on Enterprise. Exportable via API or CSV. Ingest into your own SIEM on every scan completion via webhook.

Infrastructure compliance

  • SOC 2 Type II — Pro + Enterprise. Report available under NDA.
  • ISO 27001 — certified; certificate on request.
  • GDPR — data-processor on your behalf; DPA template available.
  • CCPA — covered under the DPA.
  • HIPAA — BAA available on Business + Enterprise.
  • PCI DSS — Level 4 merchant programme; not a Level 1 service provider but compatible with customer CDE programmes.
  • FedRAMP / HIPAA High / DoD IL5 — not available; custom deployment on-prem or air-gapped is the supported path for those regimes.

Responsible disclosure

Security issues in Pentestas itself: security@pentestas.com. PGP key at https://pentestas.com/.well-known/pgp-key.txt. We respond within 24 hours. Accepted reports are credited in our security hall of fame.

Incident response (ours)

If Pentestas suspects a tenant-affecting breach:

  1. Triage within 1 hour of detection.
  2. Notification to affected tenant admins within 4 hours if confirmed.
  3. Public disclosure within 7 days (with remediation status) unless law enforcement requests delay.
  4. Full post-mortem published within 30 days.

Tenant-admin email contact is enforced during onboarding. If you haven't verified a security contact, your first invoice will remind you to.

The tl;dr for procurement

  • Tenant isolation: application + DB (RLS) + backup. Three-layer.
  • Field-level encryption with per-tenant Fernet keys.
  • BYOK supported on Enterprise. Customer KMS revocation = immediate denial.
  • TLS 1.3 for all external; mutual auth for agent connections.
  • Target credentials never persisted post-scan start.
  • SOC 2 Type II, ISO 27001, BAA-compatible.

This is the level of detail your procurement team needs. The long-form in Encryption docs has the full specifics.

Evaluate Pentestas against your procurement checklist Request SOC 2 report under NDA via hello@pentestas.com.

Further reading