How pentes.io protects your data and stays in scope
pentes.io is a security product. The credibility of the report you generate depends on the rigour of the platform that produced it. This page describes the controls we run, the ones that are architectural rather than policy, and the ones we're still maturing.
The architectural rules
These are not "policies we follow" — they are constraints the system enforces. Removing them would require rewriting the worker.
- No scan without verified ownership. The control plane refuses to enqueue a scan job for an unverified asset. The worker re-verifies the ownership artifact at the moment of job start; a mismatch fails the job and writes a tamper-evident entry to the audit log.
- Non-destructive scanner posture. The worker invokes nuclei with
-exclude-tags intrusive,exploit,dos,fuzzing,brute-force, ZAP in baseline (passive) mode, and testssl.sh in cipher-survey mode only. No active exploitation modules are wired into the worker; adding one would require a code change and a code review. - Egress lockdown. Scan workers run in disposable containers on dedicated hardware (Hetzner, Falkenstein). The host's
iptables DOCKER-USERchain restricts container egress to verified target IPs only — workers cannot make arbitrary outbound connections, including to LLM providers. - LLM has no network or shell access to targets. The triage service reads SARIF blobs plus minimal asset context (no secrets, no credentials, no raw response bodies) and returns JSON. The LLM never touches the target, never executes code on our infrastructure, and never sees customer credentials.
- Tenant isolation in every query. Every database query against assets, jobs, findings, reports, and audit log entries scopes by
org_id. There is no internal endpoint that can read across tenants. - Append-only audit log. Every security-relevant event (verification, scan start, scan completion, report access) is written to an immutable audit log. This is the legal record that backs each scan and is retained for the life of the account plus seven years.
Data protection
- In transit: TLS 1.3 on all public endpoints; HSTS with preload (2-year max-age) on pentes.io; modern cipher suites only.
- At rest: PostgreSQL volumes encrypted with AES-256 at the host layer; SARIF blobs and rendered reports stored in Cloudflare R2 with server-side encryption.
- Secrets: service-to-service credentials and third-party API keys held in a single secrets-manager source; never logged, never sent to the LLM, never embedded in audit log entries.
- Passwords: argon2id with a per-user salt and conservative memory/time parameters. Optional Google Sign-In bypasses password storage entirely.
- Backups: daily encrypted database snapshots with off-host retention; restore tested quarterly.
Application security
- HTTP response headers: strict Content-Security-Policy (first-party scripts and styles only, GA4 the sole external script), Strict-Transport-Security with preload, X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy strict-origin-when-cross-origin, Permissions-Policy deny-all for camera/mic/geo/payment APIs we don't use.
- Schema-first request validation: every API route validates the request body against a JSON schema before the handler runs.
- Rate limiting: per-account sliding window via Redis; aggressive limits on auth endpoints; per-IP fallback for unauthenticated traffic.
- Source map protection: sourcemaps emitted for internal error monitoring but never served to the public — the SPA bundle ships without the
//# sourceMappingURLcomment. - Dependency hygiene: pinned production dependencies, automated vulnerability scanning on PRs, monthly review.
Infrastructure and egress
- Scanning plane: dedicated Hetzner hardware in Falkenstein, EU; attributed PTR records (
scanner.pentes.io→ IP) so target operators and abuse desks can identify our scan traffic at a glance. - Control plane: separate network segment from the scanning plane; no shared volumes, no shared credentials.
- Sub-processors: listed in the Privacy Policy with the data each processes.
- Abuse handling: Hetzner abuse complaints are routed to security@pentes.io with the customer audit-log excerpt as evidence of authorization.
Operational practices
- Access: production access requires a hardware-key second factor; access is logged and reviewed monthly while the team is small enough to do it manually.
- Deployments: immutable container images; deploys run through a documented runbook (no manual SSH-and-edit on production).
- Logging: structured JSON application logs with request and job correlation IDs, retained 30 days for incident response.
- Incident response: on-call rotation while the team is small; documented severity ladder, customer-impact disclosure within 72 hours of confirmed breach.
What we don't yet have
Honest disclosure of the gaps we're closing:
- SOC 2 attestation — in progress, expected within 12 months of GA. We can share the readiness brief on request.
- Penetration test report — first external assessment scheduled pre-GA; results will be summarized publicly here.
- ISO 27001 — not pursued at this scale; revisit when the team or customer base requires it.
- Bug bounty program — not yet open; the responsible disclosure policy covers individual researcher reports in the meantime.
Reporting an issue
If you've found a security vulnerability in our service, the disclosure path is at /responsible-disclosure/. The short version: security@pentes.io, 90-day coordinated disclosure window, we acknowledge within 72 hours.