11 KiB
Penetration-Test Scope and Engagement Guidelines
This document is the canonical scope and ground-rules contract for any third-party penetration testing of the platform. It is referenced from SECURITY.md, from vulnerability-disclosure.md and from the public .well-known/security.txt. Engagement-specific addenda (test credentials, NDA, statement-of-work) are provided privately by the operator.
Status: template — pre-defined scope. The operator selects a test window per engagement and signs the addendum separately.
1. Engagement contact and escalation
| Role | Contact | Channel |
|---|---|---|
| Primary security contact | security@<your-domain> |
Email + PGP (see .well-known/pgp-key.txt) |
| Data-protection officer (DPO) | dpo@<your-domain> |
|
| Out-of-hours escalation | oncall@<your-domain> |
Operator-side paging |
| Coordinated-disclosure liaison | security@<your-domain> |
All initial engagement traffic must go through security@<your-domain>; secondary channels are only used after the operator confirms.
2. In-scope assets
The following systems are in scope for authorised testing. Replace <env> with the agreed environment (staging or pentest).
Web and API surface
https://app.<env>.<your-domain>— primary tenant web SSRhttps://admin.<env>.<your-domain>— admin UI (host-aware variant)https://api.<env>.<your-domain>— versioned/v1/*HTTP surfacehttps://realtime.<env>.<your-domain>— Hocuspocus collaboration WebSockethttps://app.<env>.<your-domain>/.well-known/security.txthttps://app.<env>.<your-domain>/embed/forms/*— form-widget embed surfacehttps://app.<env>.<your-domain>/api/leads/capture— marketing lead-capture endpointhttps://cdn.<env>.<your-domain>/widget.jsandmarketing.js— public widget bootstraps
Tenant data plane
Test tenants are provisioned per engagement (see §4). Cross-tenant assertions must be exercised against operator-provided tenant pairs only.
Background processing surface
Worker-internal HTTP probes (/healthz, /readyz on per-group ports 9101–9105) are out of public scope but may be exercised through documented admin endpoints exposed by the API.
Documentation surface
The repository's documentation set (docs/security/*, docs/operations/*) is in scope for review only — modifications must come via the responsible-disclosure channel.
3. Out-of-scope assets and activities
The following are explicitly out of scope and any testing against them voids the safe-harbor commitment in vulnerability-disclosure.md:
Out-of-scope assets
- Production tenants (
app.<your-domain>without<env>prefix) - Third-party provider consoles or APIs:
- Stripe (live + test), Mailjet, OpenAI / Anthropic / Scaleway / Aleph-Alpha, Bunny CDN, Cloudflare, GitHub, Sentry SaaS (if used), MeiliSearch Cloud, Qdrant Cloud
- Marketing site (
<your-domain>andwww.<your-domain>static pages) — separate engagement - Operator infrastructure outside the documented endpoints (DNS registrar, Coolify console, Postgres direct port, Redis direct port)
- Customer-configured outbound webhook destinations
- Customer-configured SSO IdPs
Out-of-scope activities
- Destructive testing — no actions that permanently delete data, corrupt backups, or DOS production / staging
- Real-user data exfiltration — no harvest of production-grade PII. If a test inadvertently surfaces production data, stop, do not store, do not share, and notify
security@<your-domain>immediately - Stripe live-mode replay — webhook replay must use Stripe CLI in test-mode against the dedicated
pentesttenant; live-mode payloads are out of scope - Mail-bomb / SMS-bomb — no testing that triggers more than 10 outbound notifications per minute to non-operator-provided addresses
- Social engineering of operator staff, customers, or third-party support — out of scope
- Physical access — out of scope
- Denial-of-service / load testing — disallowed without operator-signed addendum and a maintenance window
- Modification of test artifacts on a shared environment — each engagement gets its own tenant
- Brute-force at scale — limited bursts to demonstrate rate-limit behavior are allowed; sustained credential-stuffing campaigns are not
- Testing of public CDN edge caches — must not include cache-poisoning against shared edges
4. Test tenants and credentials
For each engagement the operator provisions:
- One dedicated
pentest-<engagement-id>tenant on<env> - Two non-admin users (Owner + Member) with synthetic email addresses (
pentest+owner-<id>@<your-domain>,pentest+member-<id>@<your-domain>) - One service API key with
pentest-readonlyscope - One service API key with
pentest-readwritescope (scoped to thepentest-<id>tenant only)
Credentials are delivered via PGP-encrypted email or 1Password share, single-use, with a 30-day TTL aligned to the engagement window.
For cross-tenant isolation tests, the operator additionally provisions a paired pentest-isolation-<engagement-id> tenant. Both tenants share a synthetic data shape but must remain logically isolated; demonstrating a cross-tenant read or write between this pair is an in-scope finding.
5. Test windows
- Default window: two consecutive weeks within an operator-confirmed slot
- Allowed hours: Monday–Friday 09:00–18:00 CET (Europe/Berlin). Off-hours testing only with written operator confirmation
- Maintenance freeze: no testing during operator-announced freezes (e.g. release nights, regulatory audit windows)
- Live-update channel:
security@<your-domain>with a daily status email; an emergency stop is honoured within one business hour
6. Expected test classes
The engagement is expected to exercise (non-exhaustive):
- OWASP Top 10 (web)
- OWASP API Security Top 10
- OWASP ASVS Level 2 — control coverage check
- Tenant isolation — cross-tenant reads / writes across all data planes (DB, cache, search, vector store, storage, mail, realtime)
- AuthN / AuthZ — session, JWT, API-key, magic-link, TOTP, recovery codes, magic-link invitation, SSO (when enabled)
- IDOR / BOLA across every
/v1/*resource - Privilege escalation — role, permission, plugin capability (where shipped)
- CSRF / clickjacking / CORS
- CSP regressions once enforcement lands
- Webhook surface — inbound signature forgery, replay, SSRF on outbound delivery
- AI surface — prompt injection (covered for tool-call surfaces), cost exhaustion, prompt-data leakage in logs
- Form-widget + lead-capture — origin spoof, embed tamper, honeypot bypass, Turnstile bypass
- Realtime (Hocuspocus) — anonymous connect, cross-document read, malformed Yjs payload
- Storage — presigned-URL forgery, key-prefix bypass, malicious upload (AV layers 1 + 2)
- Backup / snapshot CLI — restore-in-production guardrail, PII-profile leakage
Items explicitly out of scope from the test classes:
- LLM jailbreaks against generic chat surfaces — not in scope (we accept that prompt-injection mitigation is best-effort for free-form chat). Tool-call surfaces remain in scope.
- Dependency-vulnerability scanning against shipped SBOM — covered separately via SBOM workflow (see
sbom.md)
7. Reporting format
Findings are reported in Markdown, one file per finding, named YYYY-MM-DD-<short-slug>.md. Each file contains:
- Title — concise (≤ 80 chars)
- Severity — CVSS 3.1 vector + score, plus the operator severity bucket (P0–P3, see
incident-response.md) - Affected surface — generic route class, endpoint shape, worker job, or documentation page. Never a customer-specific URL
- Reproduction — minimal steps using fixtures / synthetic values only. PoC must be deterministic against the pentest tenants
- Observed impact — what happened
- Expected behavior — what should have happened
- Remediation suggestion — optional; the operator's engineers own remediation design
- Evidence — request IDs, job IDs, screenshots redacted of customer / tenant / credential material
- References — CWE, OWASP, related findings
All findings are delivered via PGP-encrypted email to security@<your-domain> or via the operator's coordinated-disclosure portal once enabled.
8. Disclosure timeline
- Acknowledgement: ≤ 48 hours from receipt
- Triage (severity assigned, owning team identified): ≤ 5 business days
- Fix window:
- P0 / Critical: emergency patch ≤ 7 calendar days
- P1 / High: ≤ 30 calendar days
- P2 / Medium: ≤ 60 calendar days
- P3 / Low: ≤ 90 calendar days
- Public disclosure: 90 days after report, or earlier on mutual agreement, or later if the operator and reporter agree that a longer fix window is justified by complexity. The operator commits to publishing a security advisory at disclosure time.
- Bug-bounty (when active): see
bug-bounty.md. Until the program is active, findings remain eligible for the coordinated-disclosure hall of fame.
9. Safe harbor
Researchers who:
- limit their activity to the in-scope assets,
- avoid the out-of-scope activities,
- respect the operator's stop request,
- report findings exclusively through
security@<your-domain>until disclosure is mutually agreed, - do not modify, destroy, or exfiltrate data beyond the minimum required to demonstrate impact
are granted safe harbor: the operator will not pursue legal action, will request that other parties also stand down, and will publicly credit the researcher on request.
10. Pre-engagement checklist (operator)
- Engagement addendum signed (scope, dates, contact, billing)
- Pentest tenants provisioned (primary + isolation-pair)
- Synthetic test data seeded
- Test credentials delivered via PGP / 1Password share with TTL
- Sentry sampling raised to 100 % for
pentest:*tags - Operator on-call paged into the engagement Slack channel
- Maintenance freeze calendar confirmed clear
- PGP public key on
.well-known/pgp-key.txtnot within 30 days of expiry - Internal IR-team briefed (severity classification, escalation path)
11. Pre-engagement checklist (researcher)
- PGP key shared and verified
- Engagement addendum signed
- Test credentials received and rotated into researcher's password manager (single-use, no sharing)
- In-scope / out-of-scope confirmed against §2 / §3
- Reporting format confirmed against §7
- Operator stop-channel acknowledged (
security@<your-domain>)