Files
HiveGrid-Wireframes/hivegrid-cloud/docs/security/plugin-audit-rfp.md
T

417 lines
20 KiB
Markdown

# Plugin Runtime External Security Audit — Request for Proposals
**Status:** Draft RFP — awaiting operator dispatch
**Phase:** Phase 06 (Plugin System), gating production rollout
**Authoring agent:** Claude Opus 4.7 (1M context), 2026-05-19
**Related blocker:** B-006 in `docs/improvement-plan/BLOCKERS.md`
**Companion document:** `docs/security/plugin-runtime-signoff.md`
> The operator dispatches this RFP. The authoring agent did **not** contact any
> firms; engagement is an operator action.
---
## 1. Vendor recommendation
### Top pick: **Cure53** (Berlin, DE)
Reasoning (4 sentences):
1. **DACH proximity + DSGVO/BDSG default operating mode.** Cure53 has been
headquartered in Berlin since 2007, operates under German contract law by
default, and is one of the few firms whose standard NDA + DPA pattern is
ready-made for §203 / BDSG / DSGVO constraints — no extra
data-processing-agreement haggling.
2. **Browser-sandbox + cryptographic-protocol pedigree maps directly onto our
surface.** Cure53's published reports cover client-side sandboxes,
end-to-end-encrypted apps (Mailvelope, Bitwarden, Tor Browser, NordVPN,
Psono, Ente, OpenPGP.js) — the same threat model we have for a WASM
sandbox + Ed25519 signature trust path. No public report explicitly named
"Wasmtime audit" is confirmed (unconfirmed as of 2026-05); their browser-VM
and JS-sandbox work is the closest adjacent track record.
3. **Report depth + remediation cycle.** Cure53 reports are public-quality by
default (we publish a sanitized version on `docs/security-reviews/`), and
one re-test pass is standard in their engagement letter — exactly what our
sign-off process needs.
4. **Budget realism.** A 3-5-day pen-test from Cure53 typically lands in the
upper half of our 15-25k EUR ceiling (unconfirmed — operator to request a
firm quote); we accept that ceiling because the alternative (a sandbox
escape post-rollout) is unbounded liability.
If the firm quote exceeds 25k EUR by more than 10%, **fall back to SySS** —
they are the German market leader in volume pentest engagements and their
mid-size scope sweet spot fits our 3-5-day brief at lower cost (DACH day-rates
of approximately 1,000-1,500 EUR per consultant; unconfirmed for SySS
specifically).
### Alternates ranked
1. **SySS GmbH** (Tübingen, DE) — German market leader in mid-size pentests,
~180 staff (over 100 in pentest delivery), founded 1998. Best if the
Cure53 quote exceeds budget. German-language reports available; English
on request. No public WASM-runtime publications confirmed as of 2026-05.
2. **Trail of Bits** (NYC, US — handles EU clients) — founded 2012 by Dan
Guido. Public WASM track record is the strongest of any firm: Manticore
added WebAssembly symbolic-execution support in 2020, they audited
wasmCloud via OSTIF, and they published the Discord E2EE WebAssembly audit
(Jun 2025). Best if our threat priority shifts toward formal verification
of the sandbox boundary. Drawback: US-based, so DSGVO data-flow gymnastics
are real; English-only delivery; budget likely exceeds 25k EUR for a
3-5-day brief.
3. **NCC Group** (Manchester, UK, with Munich office) — founded 1999. Authored
the canonical "Security Chasms of WASM" whitepaper + Black Hat USA 2018
talk "WebAssembly: A New World of Native Exploits on the Browser"
(Lukasiewicz et al.). EU presence via Munich GmbH. Best if we want a firm
that has done WASM offensive research specifically. Drawback: large firm,
so the engagement consultant assigned may be a junior — we would need to
negotiate the named-consultant clause.
4. **secfault Security** (Würzburg, DE) — small DACH boutique. Public reports
include Nitrokey NetHSM (HSM firmware) and 1Password annual pentest
(2023). Strong dev-aware reporting style + manual code review focus. Best
if we want a deep-dive code-review-heavy engagement rather than a broad
pen-test sweep. No public WASM publications confirmed as of 2026-05.
Smallest firm of the five — capacity risk if their bench is booked.
### Decision matrix
| Firm | WASM track record | EU GDPR-native | DACH language | Cal. weeks (kickoff→report) | Est. EUR (3-5 day brief) | Best-fit if … |
|---|---|---|---|---|---|---|
| **Cure53** | Adjacent (browser sandboxes, E2EE crypto); no public WASM report confirmed | Yes (Berlin, DSGVO native) | German + English | ~3 weeks | 18-25k (unconfirmed; upper-budget) | Default — best balance of proximity + reporting quality |
| SySS | None public | Yes (Tübingen, DSGVO native) | German + English | ~2-3 weeks | 10-18k (extrapolated from German day-rate norms; unconfirmed) | Budget-constrained; volume-pentest comfort zone |
| Trail of Bits | Strongest (Manticore WASM, wasmCloud, Discord E2EE WASM) | No (US, DPA required) | English only | ~4-6 weeks | 25-50k+ (US day-rates, unconfirmed for this brief) | Formal-verification depth required; budget flexible |
| NCC Group | Strongest research lineage (Black Hat 2018, "Security Chasms of WASM" whitepaper) | Partial (UK + Munich office) | English (German via Munich) | ~3-4 weeks | 20-35k (unconfirmed) | WASM offensive-research depth required |
| secfault | None public; HSM + crypto adjacencies | Yes (Würzburg, DSGVO native) | German + English | ~3-4 weeks | 12-20k (unconfirmed) | Manual code-review depth > broad pentest sweep |
**Unconfirmed values:** all EUR ranges are agent estimates from public
day-rate norms; firm quotes are required before commitment. WASM track record
for Cure53, SySS, secfault is reported as "no public WASM publications
confirmed" — these firms may have done WASM work under NDA.
---
## 2. Engagement scope (in-scope)
The audit covers the **plugin runtime + capability gateway + plugin
lifecycle** shipped during Phase 06. Concrete repository paths:
### Plugin runtime package — `packages/plugin-runtime/src/`
- `runtime.ts` — V8 `WebAssembly` host wrapper (`PluginSandbox`
interface; foundation uses Node 22's built-in `WebAssembly`, Wasmtime is the
documented upgrade path)
- `capability-gateway.ts` — deny-by-default host-fn gateway; every
capability call passes through this single chokepoint
- `capabilities.ts` — closed enum of capabilities + scope shapes
- `manifest.ts` — Zod-validated plugin manifest schema (capability declaration
+ version constraints + signing metadata)
- `signature.ts` — Ed25519 signature verification + canonical signing form;
trust anchor is `PLUGIN_TRUSTED_PUBLIC_KEYS` env allowlist
- `audit.ts` — per-invocation capability-use buffer + outbox-batched
persistence
- `crash-tracker.ts` — sandbox-crash event recording (Sentry alert path)
- `migrations.ts` — plugin-owned DB migration runner (constrained scope)
- `sanitize.ts` — output redaction (Credit-Card / JWT / IBAN / API-Key
patterns with Luhn-validated CC detection)
- `hooks/registry.ts` + `hooks/emit.ts` — hook subscription registry +
event emitter into the plugin invocation path
### Worker invocation path — `apps/worker/src/jobs/`
- `plugin-invoke.ts` — BullMQ handler that dequeues `plugin.invoke` jobs,
loads the manifest, verifies signature, instantiates the sandbox, runs the
hook, and persists the invocation outcome
- `plugin-capability-use.ts` — outbox-event consumer that bulk-inserts
`PluginCapabilityUse` rows from the gateway's batched events
- `packages/cli/src/commands/plugins/verify-audit-chain.ts` — operator CLI
that verifies the tenant-wide `PluginCapabilityUse` hash chain
### Tenant admin install + lifecycle — `apps/web/app/`
- `routes/api.tenants.$tenant.plugins.tsx` — install / grant / revoke /
enable / disable API surface (per-tenant scoped); uninstall is
CLI/operator-only in the current product surface
- `routes/app.$tenant/settings/plugins.tsx` — tenant admin UI
- `routes/app.$tenant/settings/plugins.$id.audit.tsx` — per-plugin audit
trail UI (keyset-paginated, capability + UTC date-range filter)
- `modules/plugins/services/.server/PluginLifecycleService.ts` — install /
grant / revoke / enable / disable service (signature verify + wasmSha256
rehash on every load). CLI uninstall is implemented separately as an
operator escape hatch.
- `modules/plugins/services/.server/pluginHookPublisher.ts` — host-side
hook publisher that emits invocation jobs to the worker queue
### Data model — `prisma/schema/plugins.prisma`
- `Plugin` — installed plugin per tenant (manifest, wasmSha256, public key,
enabled flag)
- `PluginUserConfig` — per-user enablement + free-form config blob
- `PluginCapabilityUse` — per-host-fn audit row (capability name, payload
hash — **never raw body** — outcome, durationMs, timestamp)
### Manifest signing trust model
- `PLUGIN_TRUSTED_PUBLIC_KEYS` env allowlist (foundation-state; a registry
+ revocation flow is deferred to the marketplace track per
`docs/improvement-plan/06-plugin-system/audit-docs.md` "Deviations")
- Ed25519 verification via `@noble/ed25519`
- Canonical signing form: sorted-keys JSON of the manifest minus the
signature / signedBy / wasmSha256 fields, concatenated with the wasm
SHA-256 hex digest, signed end-to-end (`<canonical>:<wasmSha256>`)
- Worker rehashes the wasm binary on every load and refuses to invoke when
the recorded `wasmSha256` does not match the on-disk binary
### Hook event flow
- Hook subscription declared in plugin manifest → registered into
`hooks/registry.ts` at install time → host emits via `hooks/emit.ts`
→ outbox event → BullMQ `plugin.invoke` job → worker handler →
sandbox → capability gateway → audit batch → outbox flush
### Threat-model anchor
In-scope claims that the audit MUST stress-test (sourced from
`docs/improvement-plan/06-plugin-system/wasm-sandbox.md` §Security Notes):
- Sandbox boundary is enforced by the V8 WebAssembly memory boundary +
deny-by-default capability gateway (foundation does **not** yet use
worker-thread isolation; this is the documented upgrade path)
- Per-instruction fuel is **approximated** by charging host-fn calls
through the gateway — V8 has no public hook for per-instruction metering
(this is a known limitation the audit should evaluate)
- Capability scope on `http.outbound` is enforced via host allowlist
- Capability scope on `db.*` is enforced by injected `WHERE tenantId = $tid`
(read-only at foundation level)
- Capability scope on `storage.*` is enforced via key prefix
`plugin:<id>:tenant:<tid>:`
- Tenant ID is **always host-injected, never plugin-supplied**
- No `WebAssembly.instantiate` from inside the sandbox (no dynamic-code
execution by plugins)
- Audit-log payloads store SHA-256 of arg-shape only — no raw body
(DSGVO data-minimization)
- Signature verification is enforced at install AND at every load (binary
rehash)
---
## 3. Out-of-scope
- **Hosting infrastructure** — Coolify / Docker / Postgres / Redis / Loki /
Sentry self-hosted / Authentik are covered under separate engagements (see
`docs/security/pen-test-scope.md`).
- **Other phase deliverables** — auth (Phase 01), observability (Phase 02),
scaling (Phase 03), AI/RAG (Phase 04), business features (Phase 05),
Stripe/billing migrations.
- **Marketplace UX** — not yet built. The trust model assumed by this audit
is the foundation-level `PLUGIN_TRUSTED_PUBLIC_KEYS` env allowlist; a
publisher-key registry + revocation flow is a separate future engagement.
- **Customer-authored plugins** — only the host runtime + gateway are
in-scope. A customer plugin's logic is the customer's responsibility; the
audit checks whether the host can be subverted, not whether a benign
plugin is bug-free.
- **Production tenant data** — testing happens against a dedicated
`pentest-<engagement-id>` tenant on staging (see §4 of
`docs/security/pen-test-scope.md`).
- **Per-instruction fuel correctness against an adversarial WASM binary** —
acknowledged as approximated at foundation level; the audit should flag
it as a Medium finding rather than a Critical (it is a known deviation).
---
## 4. Deliverables expected from vendor
1. **Findings report** — Critical / High / Medium / Low with either CVSS 3.1
or DREAD scoring. The operator's preference is CVSS 3.1 for
cross-referencing with NIST NVD; DREAD is acceptable if the firm
standardizes on it.
2. **Reproduction steps per finding** — explicit enough that a re-test on
our side replicates the exploit; payload bodies, test-tenant credentials
used (provided by us), and the affected file path + line range.
3. **Remediation guidance per finding** — what to change, what the residual
risk is if not changed, what the alternative mitigation is.
4. **One re-test pass included** — after we address Critical/High findings,
the firm re-tests the same exploit set and issues a re-test letter
(green / red).
5. **Sign-off letter** — once Critical and High are addressed (or
accepted-residual with operator co-signature), the firm signs the joint
sign-off document at `docs/security/plugin-runtime-signoff.md`.
6. **Public-quality executive summary** — sanitized version we publish at
`docs/security-reviews/plugin-runtime-<YYYY-MM-DD>.md`. The full report
(with exploit payloads) is archived privately at
`private/security-reviews/plugin-runtime-<YYYY-MM-DD>-full.md`.
---
## 5. Timeline expectation
- **3-5 days pen-test** (active testing window against the test tenant)
- **5-7 calendar days report writing**
- **2 days re-test** (after we ship Critical/High fixes)
- **~3 calendar weeks end-to-end** from kickoff to sign-off, assuming no
Critical finding requires a multi-week remediation.
Critical findings that require architectural change (e.g. introducing
worker-thread isolation, swapping V8 for Wasmtime) may extend the timeline
by 2-4 weeks. The operator accepts this risk in exchange for the audit
catching such issues before production rollout.
---
## 6. Budget cap
**EUR 25,000 hard cap** per B-006 (`docs/improvement-plan/BLOCKERS.md`).
- Quotes within the cap proceed directly.
- Quotes 0-10% above the cap may be negotiated down (drop the re-test pass
to "first 4 hours included, then T&M" or restrict the brief to 3 days
instead of 5).
- Quotes more than 10% above the cap require operator approval; the
fallback is the next-ranked alternate (SySS).
---
## 7. Sign-off criteria
The audit is considered complete and the production rollout is unblocked
when **all** of the following are true:
- [ ] All **Critical** findings addressed AND re-tested green by the firm.
- [ ] All **High** findings either addressed (re-tested green) OR
documented as accepted-residual-risk with operator + auditor
co-signature on the residual-risk line.
- [ ] **Medium** findings recorded in
`docs/improvement-plan/06-plugin-system/security-findings/<id>.md` as
follow-up tasks (fixed if cheap, deferred if expensive — but always
recorded).
- [ ] **Low** findings recorded in the same directory and triaged to the
backlog.
- [ ] Joint sign-off document at `docs/security/plugin-runtime-signoff.md`
filled and signed (operator + lead auditor at minimum).
- [ ] Sanitized public report archived at
`docs/security-reviews/plugin-runtime-<YYYY-MM-DD>.md`.
- [ ] Full report archived at
`private/security-reviews/plugin-runtime-<YYYY-MM-DD>-full.md`.
Only after all checkboxes are green may the operator set
`PLUGIN_RUNTIME_PRODUCTION_ENABLED=true` in the production environment.
---
## 8. Audit package contents (what we send the vendor)
A `scripts/build-plugin-audit-package.sh` script is the canonical shipping
tool for the vendor package. The operator may still add encrypted
environment-specific credentials out of band for the first engagement. The
package contains:
1. **Code tarball** — the in-scope file list from §2 of this RFP, exported
at a frozen git SHA (the SHA the audit is performed against).
2. `docs/security/threat-model.md` — overall platform threat model.
3. `docs/security/plugin-audit-rfp.md` — this RFP.
4. `docs/security/plugin-runtime-signoff.md` — sign-off template.
5. `docs/improvement-plan/06-plugin-system/wasm-sandbox.md` — design
intent + Security Notes section (the in-scope claims).
6. `docs/improvement-plan/06-plugin-system/audit-docs.md` — audit logging +
sanitization design + sign-off process.
7. **Test-tenant credentials** — provisioned per §4 of
`docs/security/pen-test-scope.md`; sent via PGP-encrypted channel to the
lead auditor.
8. **Three sample plugins** (when shipped per audit-docs.md Step 10):
benign / malicious-test / edge-case fixtures, signed with a test
publisher key whose public half is registered on the staging tenant.
---
## 9. Vendor contact instructions (operator action)
The operator dispatches one of the following email templates to the chosen
firm's `info@` or `contact@` address. **The authoring agent did not contact
any firm.**
### Email template (English)
```
Subject: RFP — WASM plugin runtime security audit, ~3-5 days, EUR <=25k
Hello <firm>,
We are requesting a proposal for an external security audit of our
WebAssembly-based plugin runtime, capability gateway, and plugin
lifecycle. The system is written in TypeScript (Node 22, V8 WebAssembly
host), with Ed25519 signature verification and per-tenant capability
scoping.
Scope summary:
- 3-5 days active pen-test
- WASM sandbox boundary + capability gateway + signature trust model +
audit logging + plugin lifecycle
- Frozen git SHA on a dedicated staging test tenant
- Report with Critical/High/Medium/Low findings, one re-test pass included
- Joint sign-off after remediation
Budget: hard cap EUR 25,000. Target timeline: kickoff → sign-off in ~3
calendar weeks.
We can share the full audit package (RFP, design docs, threat model,
code tarball at the frozen SHA, test-tenant credentials via PGP) on
NDA. Please reply with availability, your statement-of-work template,
and a ballpark price for this scope.
Best regards,
<operator name>
<operator email>
<operator PGP fingerprint>
```
### Email template (Deutsch — for SySS, secfault, Cure53)
```
Betreff: Anfrage — externe Security-Audit unserer WASM-Plugin-Runtime,
3-5 Tage, EUR <=25k
Guten Tag <Firma>,
wir möchten ein Angebot für einen externen Security-Audit unserer
WebAssembly-basierten Plugin-Runtime, Capability-Gateway und
Plugin-Lifecycle einholen. Das System ist in TypeScript implementiert
(Node 22, V8 WebAssembly Host) mit Ed25519-Signatur-Verifikation und
per-Mandant-Capability-Scoping.
Scope:
- 3-5 Tage aktiver Pentest
- WASM-Sandbox-Boundary + Capability-Gateway + Signatur-Vertrauensmodell
+ Audit-Logging + Plugin-Lifecycle
- Frozener Git-SHA gegen dediziertes Staging-Test-Mandant
- Report mit Critical/High/Medium/Low Findings, ein Re-Test inkl.
- Gemeinsames Sign-off nach Remediation
Budget: harte Obergrenze EUR 25.000. Ziel-Timeline: Kickoff → Sign-off
in ca. 3 Kalenderwochen.
Audit-Paket (RFP, Design-Docs, Threat-Model, Code-Tarball am frozen
SHA, Test-Mandant-Credentials via PGP) senden wir nach NDA-Unterzeichnung.
Bitte antworten Sie mit Verfügbarkeit, SoW-Template und einer
Preis-Indikation für diesen Scope.
Mit freundlichen Grüßen,
<Operator-Name>
<Operator-E-Mail>
<Operator-PGP-Fingerprint>
```
**Operator action checklist:**
- [ ] Send to top pick (Cure53). Wait 5 business days.
- [ ] If no response or quote out of budget: send to fallback (SySS).
- [ ] If still no response: send to alternate 2 (Trail of Bits) — accept
English-only delivery and a likely budget overrun.
- [ ] On firm acceptance: sign NDA + SoW, share audit package, schedule
kickoff call.
- [ ] After kickoff: provision test-tenant credentials, share PGP-encrypted.
- [ ] After report received: file findings into
`docs/improvement-plan/06-plugin-system/security-findings/`, assign
each Critical/High to an agent for remediation.
- [ ] After remediation: request re-test from firm.
- [ ] After re-test green: fill in
`docs/security/plugin-runtime-signoff.md`, both parties sign.
- [ ] Flip `PLUGIN_RUNTIME_PRODUCTION_ENABLED=true` in production env.