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

20 KiB

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.