177 lines
11 KiB
Markdown
177 lines
11 KiB
Markdown
# 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`](../../SECURITY.md), from [`vulnerability-disclosure.md`](./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>` | Email |
|
||
| Out-of-hours escalation | `oncall@<your-domain>` | Operator-side paging |
|
||
| Coordinated-disclosure liaison | `security@<your-domain>` | Email |
|
||
|
||
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 SSR
|
||
- `https://admin.<env>.<your-domain>` — admin UI (host-aware variant)
|
||
- `https://api.<env>.<your-domain>` — versioned `/v1/*` HTTP surface
|
||
- `https://realtime.<env>.<your-domain>` — Hocuspocus collaboration WebSocket
|
||
- `https://app.<env>.<your-domain>/.well-known/security.txt`
|
||
- `https://app.<env>.<your-domain>/embed/forms/*` — form-widget embed surface
|
||
- `https://app.<env>.<your-domain>/api/leads/capture` — marketing lead-capture endpoint
|
||
- `https://cdn.<env>.<your-domain>/widget.js` and `marketing.js` — public widget bootstraps
|
||
|
||
### Tenant data plane
|
||
|
||
Test tenants are provisioned per engagement (see [§4](#4-test-tenants-and-credentials)). 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`](./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>` and `www.<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 `pentest` tenant; 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-readonly` scope
|
||
- One service API key with `pentest-readwrite` scope (scoped to the `pentest-<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`](./sbom.md))
|
||
|
||
## 7. Reporting format
|
||
|
||
Findings are reported in Markdown, one file per finding, named `YYYY-MM-DD-<short-slug>.md`. Each file contains:
|
||
|
||
1. **Title** — concise (≤ 80 chars)
|
||
2. **Severity** — CVSS 3.1 vector + score, plus the operator severity bucket (P0–P3, see [`incident-response.md`](./incident-response.md))
|
||
3. **Affected surface** — generic route class, endpoint shape, worker job, or documentation page. **Never** a customer-specific URL
|
||
4. **Reproduction** — minimal steps using fixtures / synthetic values only. PoC must be deterministic against the pentest tenants
|
||
5. **Observed impact** — what happened
|
||
6. **Expected behavior** — what should have happened
|
||
7. **Remediation suggestion** — optional; the operator's engineers own remediation design
|
||
8. **Evidence** — request IDs, job IDs, screenshots redacted of customer / tenant / credential material
|
||
9. **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`](./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.txt` not 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>`)
|