Status: pre-launch. This evidence reflects implemented code and deployed infrastructure. Provii is not yet serving end-user production traffic, so production operational metrics and audit history are not yet available. downpipes is in production for Maelstrom’s own Cloudflare estate (we run our own product), but is not yet serving external customer production traffic.
Two platforms, one ISMS. Maelstrom AI builds two products under one ISMS — Provii (privacy-preserving age verification via zero knowledge proofs) and downpipes (no-custody backup & disaster recovery for the Cloudflare data layer). This document is cross-cutting: it evidences the third-party dependencies, vendor relationships and supply-chain controls of Maelstrom AI as an organisation, across both platforms. Because downpipes is no-custody — the engine and console run in the customer’s own Cloudflare account, under the customer’s own keys, and Maelstrom holds no customer keys, data or Cloudflare tokens — downpipes adds no sub-processor for customer data (see Sub-Processors & Data Processing). The downpipes supply chain adds one Maelstrom-operated surface to this register: the static, signature-pinned update channel (
updates.downpipes.io), covered under Supply Chain Security.
Third-Party Dependencies & Vendor Management Evidence
Document Version: 1.1 Date: 2026-06-19 Author: Maelstrom AI Control Scope: UC-070, UC-144 through UC-148 (Vendor/Supply Chain Management)
Executive Summary
This document provides evidence of Maelstrom AI’s third-party dependencies, vendor relationships, and supply chain security controls across both platforms — Provii and downpipes. The evidence demonstrates:
- Complete vendor inventory (critical cloud providers, development tools, package registries)
- dependency tracking across Rust, JavaScript/TypeScript, Android, and iOS ecosystems
- SLSA Level 3 supply chain security implementation, complemented by the downpipes signature-pinned update channel (pull-only, verified against a pinned public key, signed by an offline-held update key)
- Automated security scanning via Dependabot, cargo audit, and npm audit
- Licence compliance across open source and source-available dependencies (Provii: AGPL-3.0-only, Apache-2.0, MIT, some proprietary; crates dual MIT OR Apache-2.0. downpipes: engine/console/control-plane source-available under Elastic License v2, with an MIT offline reader)
- Signed commits and verified builds designed to ensure artefact integrity
- No additional sub-processor for downpipes customer data: under the no-custody model the engine and console run in the customer’s own Cloudflare account under the customer’s keys, so Maelstrom processes no downpipes customer data and engages no sub-processor for it
Table of Contents
- Critical Third-Party Vendors
- Rust Dependencies (Cargo)
- JavaScript/TypeScript Dependencies (npm)
- Mobile Dependencies
- Supply Chain Security
- Dependency Security Scanning
- Licence Compliance
- Sub-Processors & Data Processing
- Control Mapping
Critical Third-Party Vendors
1. Cloudflare (Critical - Complete Service Dependency)
Services Used:
- Cloudflare Workers (serverless compute)
- Cloudflare KV (key-value storage)
- Cloudflare Durable Objects (stateful compute)
- Cloudflare Workers Assets (static site serving)
- Cloudflare Workers Logs (structured
console.logJSON shipped to Grafana Loki) - Cloudflare DDoS Protection
- Cloudflare Secrets Store
- Cloudflare R2 (object storage — Provii backups; downpipes backup destinations; and the static, signature-pinned downpipes update channel
updates.downpipes.io)
Criticality: HIGH - Complete infrastructure dependency
downpipes application: Cloudflare is also the substrate for downpipes, but under the no-custody model the responsibility split differs. The downpipes engine and console run in the customer’s own Cloudflare account, under the customer’s own keys — that Cloudflare tenancy is the customer’s own infrastructure, not a Maelstrom vendor relationship or sub-processor. Maelstrom operates only two content-free downpipes surfaces on its own Cloudflare account: the vendor-side control-plane (Cloudflare Workers; mints licence tokens and receives a content-free advisory beacon; holds no customer keys, data or Cloudflare tokens; fail-open — never gates backup or restore) and the static, signature-pinned update channel (updates.downpipes.io, Cloudflare R2; pull-only, no phone-home). The downpipes Licence Signer is held in Cloudflare Secrets Store on the fail-open control-plane (see Cryptographic Key Management).
Security Assessment:
- ✅ SOC 2 Type II certified
- ✅ ISO 27001 certified
- ✅ Enterprise SLA (99.99% uptime)
- ✅ Regular security audits published
- ✅ GDPR-compliant data processing
Contract Terms:
- Data Processing Agreement in place
- Security and privacy provisions
- Incident notification requirements
- Right to audit
Monitoring:
- status.cloudflare.com for outages
- Security advisories reviewed
- Annual contract review
Evidence:
provii-verifier/wrangler.toml- Production configurationprovii-issuer/worker/wrangler.toml- Issuer service configuration/trust/security/supplier-management.md- Vendor management documentation
Data Flows:
- Verifier API: Challenge storage (5-minute TTL, enforced by KV
expiration_ttlatprovii-verifier/src/routes/challenge.rs:854), audit logs (90-day retention, enforced by KVexpiration_ttl(7_776_000)atprovii-verifier/src/routes/csp_report.rs:293, which comments “TTL: 90 days matching audit log retention”; critical security event logs are retained for up to 365 days) - Issuer API: Encrypted credential issuance, officer authentication
- All services: IP address logging (90-day retention for abuse prevention, hashed via HMAC-SHA-256 keyed by
PII_HASH_KEYbefore persistence; critical security event logs are retained for up to 365 days) - downpipes control-plane: licence-token issuance and a content-free advisory beacon only — no customer keys, data or Cloudflare tokens
- downpipes update channel (
updates.downpipes.io, R2): static, signature-pinned engine update artefacts, served read-only and pulled by the engine; carries no customer data
2. GitHub (Critical - Development Dependency)
Services Used:
- GitHub source control (Git hosting)
- GitHub Actions (CI/CD pipelines)
- GitHub Packages (artefact hosting)
- GitHub Advanced Security (Dependabot, CodeQL, secret scanning)
- GitHub Container Registry
Criticality: HIGH - Development and deployment dependency (both platforms)
GitHub hosts the source repositories and CI/CD for both platforms — Provii (provii-verifier, provii-issuer, provii-crypto, the mobile wallet, SDKs, agegate-rust, etc.) and downpipes (downpipes-engine, downpipes-console, downpipes-control-plane and the MIT offline reader). It is a development tool, not a production sub-processor of end-user personal data, and is tracked under UC-070 and UC-144 rather than UC-147.
Security Assessment:
- ✅ SOC 2 Type II certified
- ✅ GitHub Advanced Security features enabled
- ✅ Bug bounty program
- ✅ Regular security updates
- ✅ SLSA Level 3 build infrastructure
Contract Terms:
- GitHub Enterprise Cloud agreement
- Data Protection Addendum
- Security features included
Monitoring:
- GitHub status page
- Security advisories
- Dependabot alerts
Evidence:
provii-verifier/.github/workflows/ci.yml- CI pipelineprovii-agegate/.github/workflows/secure-build.yml- SLSA Level 3 buildprovii-mobile-sdk/.github/workflows/secure-build.yml- Secure build pipelineprovii-agegate/.github/dependabot.yml- Dependency scanningprovii-issuer/.github/dependabot.yml- Dependabot config
3. npm Registry (Medium - JavaScript Build Tooling)
Services Used:
- npm package registry (build-time development dependencies for TypeScript repos)
- npm provenance (SLSA attestations for internal build artefacts)
Criticality: MEDIUM - Build-time dependency resolution for TypeScript services and tooling
provii-agegate ships via CDN only (cdn.provii.app). There is no npm package for provii-agegate. npm is used as a build-time dependency manager for the TypeScript projects (admin-portal, provii-management, provii-docs, provii-agegate build toolchain) but not as a distribution channel for the browser SDK.
Security Assessment:
- SRI hashes on CDN-served provii-agegate bundles
- npm audit integration for build-time dependencies
- Hermetic builds with package-lock.json
- 2FA required for npm publishing (internal tooling only)
Supply Chain Controls:
- Hermetic builds with package-lock.json
- SLSA Level 3 provenance generation
- Sigstore keyless signing for CDN bundles
- SRI hash generation for browser bundles
Evidence:
provii-agegate/.github/workflows/secure-build.yml- CDN publish and SRI hash generation
4. Crates.io (Medium - Rust Package Registry)
Services Used:
- Rust crate registry (dependency resolution)
Criticality: MEDIUM - Build-time dependency only
Security Assessment:
- ✅ cargo audit integration
- ✅ Cargo.lock hermetic builds
- ✅ Crate verification
Supply Chain Controls:
- All Rust projects use Cargo.lock for deterministic builds
- cargo audit runs in CI/CD (deny warnings)
- cargo deny for licence compliance
Evidence:
provii-verifier/.github/workflows/ci.yml- Lines 74-85 (cargo audit)provii-issuer/.github/workflows/security-audit.yml- security scanning
5. CocoaPods / Swift Package Manager (Low - iOS Dependency Management)
Services Used:
- CocoaPods registry (YubiKit dependency)
Dependencies:
- YubiKit (YubiKey hardware authentication)
Criticality: LOW - Single optional hardware authentication dependency
Evidence:
provii/ios/Podfile- iOS dependency specification
6. Maven Central / Google Maven (Low - Android Dependency Management)
Services Used:
- Maven Central (Android libraries)
- Google Maven (AndroidX, Compose)
Criticality: LOW - Standard Android development dependencies
Evidence:
provii/android/app/build.gradle.kts- Android dependency specification
Rust Dependencies (Cargo)
Core Cryptographic Dependencies
Critical Zero knowledge Proof Libraries:
File: provii-crypto/Cargo.toml
# Core cryptography dependencies
bellman = { version = "0.14", default-features = false, features = ["groth16"] }
bls12_381 = "0.8"
jubjub = "0.10"
redjubjub = "0.8"
blake2 = "0.10"
blake2s_simd = "1.0"
sha2 = "0.10"
secp256k1 = "0.31.1"
blstrs = "0.7"
# Zero-knowledge proof utilities
ff = "0.13"
group = "0.13"
rand_core = "0.6"
rand = "0.8"
subtle = "2.6"
zcash_proofs = { version = "0.24", default-features = false }
zcash_primitives = { version = "0.24", default-features = false }
sapling-crypto = { version = "0.5", default-features = false, features = ["circuit"] }
Security Properties:
- All cryptographic libraries are widely-audited open source projects
- bellman: Groth16 zk-SNARK implementation (used by Zcash, extensively audited)
- bls12_381: BLS12-381 elliptic curve (IETF standard)
- jubjub: Twisted Edwards curve (Zcash Sapling protocol)
- redjubjub: Schnorr signatures on Jubjub curve
Licence: All MIT OR Apache-2.0 (permissive, no copyleft)
Verifier API Dependencies
File: provii-verifier/Cargo.toml
Core Runtime:
worker = "=0.6.1" # Cloudflare Workers runtime
worker-kv = "=0.9.0" # KV storage client
getrandom = { version = "0.2", features = ["js"] } # WASM-compatible RNG
Cryptography:
sha2 = "0.10"
blake2 = "0.10"
blake3 = "1.5"
base64 = "0.22"
hmac = "0.12"
zeroize = { version = "1.7", features = ["derive"] }
argon2 = { version = "0.5", features = ["std"] }
Serialization:
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
prost = "0.12" # Protocol Buffers
Lints Configuration (Lines 111-133):
[lints.rust]
unsafe_code = "forbid" # No unsafe Rust allowed
missing_docs = "warn"
[lints.clippy]
unwrap_used = "warn"
expect_used = "warn"
panic = "warn"
This demonstrates secure coding practices enforcement at the compiler level.
Issuer API Dependencies
File: provii-issuer/worker/Cargo.toml
WebAuthn Support:
p256 = { version = "0.13", features = ["ecdsa"] } # P-256 ECDSA
ecdsa = { version = "0.16", features = ["verifying", "der"] }
Key Derivation:
hkdf = "0.12" # HMAC-based Key Derivation Function
aes-gcm = "0.10" # Envelope encryption for signing keys
argon2 = { version = "0.5", features = ["std"] } # API key hashing
Compression:
flate2 = { version = "1", default-features = false, features = ["rust_backend"] }
Wallet SDK Dependencies
File: provii-mobile-sdk/Cargo.toml
Cross-Platform FFI:
uniffi = { version = "0.29", features = ["cli"] } # Foreign Function Interface
uniffi_build = { version = "0.29", features = ["build"] }
Networking (HTTP/3):
quinn = "=0.11.7" # QUIC implementation
h3 = "=0.0.8" # HTTP/3
h3-quinn = "=0.0.10" # HTTP/3 over QUIC
rustls = { version = "0.23", default-features = false, features = ["ring"] }
webpki-roots = "0.26" # Root CA certificates
Parallel Proving:
rayon = "1.11" # Thread pool for parallel proof generation
JavaScript/TypeScript Dependencies (npm)
provii-agegate Browser SDK
File: provii-agegate/package.json
Production Dependencies:
{
"dependencies": {
"qrcode": "^1.5.4", // QR code generation
"zod": "^3.25.64" // Runtime type validation
}
}
Development Dependencies (Lines 45-78):
Security Tools:
"eslint-plugin-security": "^3.0.1", // Security linting
"eslint-plugin-sonarjs": "^3.0.2", // Code quality
"@stryker-mutator/core": "^9.0.1", // Mutation testing
"@playwright/test": "^1.53.0" // E2E testing
Build Tools:
"esbuild": "^0.25.5", // Fast bundler
"typescript": "^5.8.3", // Type safety
"terser": "^5.42.0" // Minification
Testing:
"jest": "^29.7.0", // Unit testing
"fast-check": "^4.3.0" // Property-based testing
OpenAPI:
"openapi-typescript": "^7.8.0", // Type generation from OpenAPI spec
"openapi-typescript-fetch": "^2.2.0" // Type-safe API client
Total Dependencies: 79 (2 production, 77 development)
Mobile Dependencies
Android Dependencies
File: provii/android/app/build.gradle.kts
Core Android Libraries (Lines 135-151):
// Core Android
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.activity:activity-compose:1.8.2")
// Compose (UI framework)
implementation(platform("androidx.compose:compose-bom:2024.02.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material3:material3")
implementation("com.google.android.material:material:1.11.0")
Security (Lines 161-163):
implementation("androidx.security:security-crypto:1.1.0-alpha06") // EncryptedSharedPreferences
implementation("androidx.biometric:biometric:1.1.0") // Biometric authentication
Camera & QR (Lines 165-172):
implementation("androidx.camera:camera-camera2:1.3.1")
implementation("androidx.camera:camera-lifecycle:1.3.1")
implementation("androidx.camera:camera-view:1.3.1")
implementation("com.google.mlkit:barcode-scanning:17.2.0") // Google ML Kit
implementation("com.google.zxing:core:3.5.3") // QR code generation
YubiKey Support (Lines 174-177):
implementation("com.yubico.yubikit:android:2.8.0") // Core Android module
implementation("com.yubico.yubikit:yubiotp:2.8.0") // OTP module
Dependency Injection (Lines 156-159):
implementation("com.google.dagger:hilt-android:2.48")
ksp("com.google.dagger:hilt-compiler:2.48")
Networking (Lines 179-181):
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
Image Loading (Lines 186-188):
implementation("io.coil-kt:coil-compose:2.5.0") // Image loading
implementation("io.coil-kt:coil-svg:2.5.0") // SVG support
Total Android Dependencies: ~40 libraries
iOS Dependencies
File: provii/ios/Podfile
CocoaPods Dependencies:
platform :ios, '17.0'
pod 'YubiKit' # YubiKey hardware authentication (Lightning + NFC)
Build Configuration (Lines 34-60):
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '17.0'
config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end
Total iOS Dependencies: 1 CocoaPod (YubiKit), rest are Apple frameworks
Supply Chain Security
SLSA Level 3 Implementation
Evidence:
/trust/developers/supply-chain-security.mdxprovii-agegate/.github/workflows/secure-build.ymlprovii-mobile-sdk/.github/workflows/secure-build.yml
SLSA Requirements Implementation:
| Requirement | Status | Evidence |
|---|---|---|
| Build as Code | ✅ | All workflows in .github/workflows/ |
| Ephemeral Environment | ✅ | GitHub-hosted runners (fresh per build) |
| Isolated Builds | ✅ | No privileged access, minimal permissions |
| Hermetic Builds | ✅ | Cargo.lock, package-lock.json enforced |
| Signed Provenance | ✅ | SLSA provenance via slsa-github-generator |
| Non-falsifiable | ✅ | Signed with GitHub OIDC tokens |
| Two-person Review | ⚠️ | Not applicable for sole-operator; signed provenance and hermetic builds provide compensating controls |
Hermetic Build Verification
provii-agegate (Lines 48-54 in secure-build.yml):
- name: Verify package-lock.json exists (hermetic build requirement)
run: |
if [[ ! -f package-lock.json ]]; then
echo "❌ package-lock.json missing - required for reproducible builds"
exit 1
fi
echo "✅ package-lock.json present"
provii-mobile-sdk (Lines 50-56 in secure-build.yml):
- name: Verify Cargo.lock exists (hermetic build requirement)
run: |
if [[ ! -f Cargo.lock ]]; then
echo "❌ Cargo.lock missing - required for reproducible builds"
exit 1
fi
echo "✅ Cargo.lock present"
Cryptographic Signing (Sigstore)
provii-agegate (Lines 196-236 in secure-build.yml):
- name: Install Cosign
uses: sigstore/cosign-installer@v3
with:
cosign-release: v2.4.1
- name: Sign npm tarball
env:
COSIGN_EXPERIMENTAL: "true"
run: |
TARBALL=$(ls provii-agegate-*.tgz)
cosign sign-blob \
--bundle "${TARBALL}.cosign-bundle" \
"${TARBALL}"
- name: Sign browser bundle
env:
COSIGN_EXPERIMENTAL: "true"
run: |
cosign sign-blob \
--bundle dist/agegate.browser.js.cosign-bundle \
dist/agegate.browser.js
Properties:
- Keyless signing (no long-lived keys to leak)
- OIDC-based authentication via GitHub
- Signatures logged in Rekor transparency log
- Non-repudiable cryptographic proof of origin
SLSA Provenance Generation
provii-agegate (Lines 254-267 in secure-build.yml):
provenance:
name: Generate SLSA Provenance
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
with:
base64-subjects: "${{ needs.sign-artifacts.outputs.hashes }}"
provenance-name: "provii-agegate.intoto.jsonl"
upload-assets: true
private-repository: true
provii-mobile-sdk (Lines 480-492 in secure-build.yml):
provenance:
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
with:
base64-subjects: "${{ needs.sign-artifacts.outputs.hashes }}"
provenance-name: "provii-mobile-sdk.intoto.jsonl"
upload-assets: true
Provenance Includes:
- Build command and environment variables
- Source repository and commit SHA
- Builder identity (GitHub Actions)
- All input materials (dependencies with hashes)
- Output artefact hashes
SRI Hash Generation (Browser Bundles)
provii-agegate (Lines 132-145 in secure-build.yml):
- name: Generate SRI hash for browser bundle
run: |
# Generate SHA-384 SRI hash (standard for CDN integrity)
SRI_HASH=$(openssl dgst -sha384 -binary dist/agegate.browser.js | openssl base64 -A)
echo "sha384-${SRI_HASH}" > dist/agegate.browser.js.sri
echo "✅ SRI hash generated:"
cat dist/agegate.browser.js.sri
- name: Generate checksums for all artifacts
run: |
cd dist
sha256sum *.js *.cjs *.d.ts > CHECKSUMS.txt
cat CHECKSUMS.txt
This allows browsers to verify integrity:
<script
src="https://cdn.provii.app/sdk/provii-agegate/v0.1.1/agegate.browser.js"
integrity="sha384-..."
crossorigin="anonymous"></script>
downpipes Update Channel (signature-pinned delivery)
downpipes extends the supply-chain story with its own delivery mechanism for the in-tenant engine, designed so that a Maelstrom-side compromise cannot silently push code into a customer’s Cloudflare account:
- Pull, never push. The engine pulls verified updates from a static, signature-pinned Cloudflare R2 bucket (
updates.downpipes.io); there is no phone-home and no standing inbound path from Maelstrom into the customer tenant (“runs dark”). - Signature verification before apply. The engine verifies each update’s signature against a pinned public key before applying it. Update artefacts are signed by the downpipes Update Signer, which is held offline by the operator and is never deployed to any Worker (see Cryptographic Key Management and the Asset Register, CRYPTO-009).
- Canary-gated safe-apply with automatic rollback. Updates are canary-gated; a bad update is automatically rolled back, limiting blast radius in customer deployments.
- Vendor surfaces are content-free. Neither the update channel nor the control-plane carries customer keys, data or Cloudflare tokens.
This is the downpipes analogue of SLSA provenance and Sigstore signing for Provii artefacts: cryptographically verified, non-pushed delivery with a key held outside the runtime.
Dependency Security Scanning
Dependabot Configuration
provii-agegate (provii-agegate/.github/dependabot.yml):
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule: { interval: weekly }
open-pull-requests-limit: 10
commit-message: { prefix: "build:" }
provii-issuer (provii-issuer/.github/dependabot.yml):
Rust Dependencies (Lines 3-43):
- package-ecosystem: "cargo"
directory: "/worker"
schedule:
interval: "weekly"
day: "monday"
time: "02:00"
open-pull-requests-limit: 10
reviewers:
- "provii-security-team"
commit-message:
prefix: "deps"
prefix-development: "deps-dev"
labels:
- "dependencies"
- "rust"
- "security"
ignore:
# Ignore major version updates for critical deps
- dependency-name: "worker"
update-types: ["version-update:semver-major"]
- dependency-name: "wasm-bindgen"
update-types: ["version-update:semver-major"]
groups:
crypto:
patterns:
- "sha*"
- "blake2"
- "hmac"
- "aes-gcm"
- "bls12_381"
- "jubjub"
GitHub Actions (Lines 88-98):
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 5
labels:
- "dependencies"
- "github-actions"
- "ci-cd"
cargo audit Integration
provii-verifier CI (provii-verifier/.github/workflows/ci.yml, Lines 74-85):
security:
name: Security Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install cargo-audit
run: cargo install cargo-audit
- name: Run security audit
run: cargo audit
provii-issuer Security Audit (provii-issuer/.github/workflows/security-audit.yml):
Daily Scheduled Scans (Lines 9-11):
schedule:
# Run daily at 2 AM UTC
- cron: '0 2 * * *'
Scanning (Lines 18-47):
cargo-audit:
name: Cargo Audit - Dependency Vulnerabilities
steps:
- name: Install cargo-audit
run: cargo install cargo-audit --locked
- name: Run cargo audit
run: |
cd worker
cargo audit --deny warnings --deny unmaintained --deny unsound --deny yanked
continue-on-error: false
Licence Compliance (Lines 49-62):
cargo-deny:
name: Cargo Deny - License & Security Compliance
steps:
- name: Install cargo-deny
uses: taiki-e/install-action@cargo-deny
- name: Run cargo deny
run: |
cd worker
cargo deny check --hide-inclusion-graph
Dependency Review (Lines 64-76):
dependency-review:
name: Dependency Review
if: github.event_name == 'pull_request'
steps:
- name: Dependency Review
uses: actions/dependency-review-action@v4
with:
fail-on-severity: high
deny-licenses: GPL-3.0, AGPL-3.0
Trivy Vulnerability Scanner (Lines 78-98):
rust-security-scan:
steps:
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: 'worker'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy results to GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
CodeQL Analysis (Lines 100-117):
codeql-analysis:
steps:
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: 'rust'
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
npm audit Integration
provii-agegate secure-build (Lines 59-60):
- name: Run security audit
run: npm audit --audit-level high
Fails the build if any high-severity vulnerabilities are found.
Licence Compliance
Rust Crates Licence Policy
File: provii-crypto/Cargo.toml (Line 25)
license = "MIT OR Apache-2.0"
All Maelstrom AI Rust crates use dual licensing:
- MIT License (permissive, allows commercial use)
- Apache License 2.0 (permissive, includes patent grant)
Third-party Rust dependencies are predominantly:
- MIT OR Apache-2.0 (bellman, bls12_381, jubjub, etc.)
- MIT (serde, tokio, anyhow, thiserror)
- Apache-2.0 (some cryptographic libraries)
Enforcement: cargo deny checks for GPL-3.0, AGPL-3.0 violations (Lines 74-76 in security-audit.yml):
with:
fail-on-severity: high
deny-licenses: GPL-3.0, AGPL-3.0
JavaScript Licence Policy
provii-agegate uses the MIT licence for production dependencies:
- qrcode: MIT
- zod: MIT
Development dependencies are not distributed, so licensing is more permissive.
Mobile Licence Compliance
Android:
- AndroidX: Apache 2.0
- Jetpack Compose: Apache 2.0
- YubiKit: Apache 2.0
- All Google libraries: Apache 2.0
iOS:
- YubiKit: Apache 2.0
- Apple frameworks: Proprietary (included with Xcode)
No GPL/AGPL dependencies in production builds.
Platform Outbound Licensing (first-party code)
The cargo-deny policy above governs the inbound third-party dependency licences for the Provii Rust crate set. The outbound licences under which Maelstrom AI distributes its own first-party code differ per platform and per repository:
| Platform | Component | Licence | Type |
|---|---|---|---|
| Provii | Repositories (per-repo mix) | AGPL-3.0-only, Apache-2.0, MIT, with some proprietary | Open source / proprietary mix |
| Provii | Rust crates (e.g. provii-crypto) | MIT OR Apache-2.0 (dual) | Open source (permissive) |
| downpipes | engine, console, control-plane | Elastic License v2 | Source-available (not open source, not AGPL) |
| downpipes | offline reader (downpipe, Go + TypeScript) | MIT | Open source (permissive) |
downpipes licensing note. The downpipes engine, console and control-plane are source-available under the Elastic License v2 — source is published, and customers are free to self-host and to back up and restore, but the software may not be resold as a managed service (a third party running it would take custody, defeating the no-custody design). The offline reader is MIT open source, and is built from a frozen public format specification so that archives can be restored from archive bytes plus the customer’s offline key with no vendor and no network in the loop. ELv2 is a source-available, not an open source, licence; the cargo-deny GPL/AGPL denial above applies to the Provii crate build and does not bear on the downpipes outbound licences.
Sub-Processors & Data Processing
The canonical sub-processor roster, complete with per-processor data-flow tables, DPA references, audit rights, and transfer mechanisms, is maintained at /trust/legal/sub-processors (version 1.1, effective 14 April 2026). This section summarises the production sub-processors engaged for the age verification platform and the docs interactive sandbox. It is reconciled against the canonical list on every management review.
downpipes adds no sub-processor for customer data. Maelstrom AI’s second platform, downpipes (no-custody backup & disaster recovery for the Cloudflare data layer), runs in the customer’s own Cloudflare account, under the customer’s own keys. The engine and console are deployed in the customer’s tenancy; archives are sealed under customer-held keys (break-glass, operational and archive-signer keys, generated by the customer) and written via a 3-2-1 fan-out to customer-controlled destinations. Maelstrom holds no customer keys, data or Cloudflare tokens at any time. Because no customer personal data is received or processed by, or on behalf of, Maelstrom for downpipes, Maelstrom is not a processor of downpipes customer data and engages no sub-processor for it. The two Maelstrom-operated downpipes surfaces — the vendor-side control-plane (mints licence tokens, receives a content-free advisory beacon; fail-open) and the static, signature-pinned update channel (
updates.downpipes.io) — run on the Cloudflare infrastructure already listed below and carry no customer keys or data, so they introduce no additional sub-processor and no international transfer of customer personal data. The sub-processors enumerated in this section are therefore those of the Provii platform and the administrator plane that supports it. See the Sub-Processors List for the canonical roster.
Infrastructure sub-processors
Cloudflare, Inc. operates as a data processor and handles hashed source IP addresses (HMAC-SHA-256 keyed by PII_HASH_KEY), challenge nonces (ephemeral), pseudonymous session identifiers, sandbox credential identifiers with docs-sbx-* and mwallet-sbx-* prefixes, request and response bodies traversing the Workers runtime, and audit and security telemetry events.
| Field | Detail |
|---|---|
| Data location | Cloudflare global edge network; traffic served from the data centre nearest the requester |
| GDPR compliance | Cloudflare master Data Processing Addendum, EU SCCs (Decision 2021/914, Module 2), UK IDTA for UK transfers |
| Security certifications | SOC 2 Type II, ISO 27001, ISO 27018, PCI DSS Level 1 for relevant services |
| Encryption | TLS 1.3 in transit, AES-256-GCM at rest |
Mobile attestation sub-processors
Apple Inc. operates the App Attest service as a data processor for the attestation result returned to Provii. It handles Apple-issued attestation public key, attestation receipt, app bundle identifier, and key identifier. It does not receive an Apple ID, device serial number, IDFA, or email address. Its purpose is to mitigate credential cloning and emulator abuse on the iOS Provii wallet at issuance.
| Field | Detail |
|---|---|
| Data location | Apple-operated infrastructure |
| GDPR compliance | Apple Developer Program Licence Agreement with Schedule 2 (DPA) |
| Purpose | Hardware-backed attestation for iOS wallet at issuance |
Google LLC operates the Play Integrity API as a data processor for the attestation verdict returned to Provii. It handles the Play Integrity verdict (app integrity, device integrity, licence verdict, Play Protect verdict), nonce supplied by provii-issuer, package name, and certificate hash. It does not receive a Google account identifier, advertising identifier, or precise location. Its purpose is to mitigate credential cloning, repackaging attacks, and emulator abuse on the Android Provii wallet at issuance.
| Field | Detail |
|---|---|
| Data location | Google global infrastructure |
| GDPR compliance | Google Play Developer Distribution Agreement with Data Processing and Security Terms |
| Purpose | Device-integrity attestation for Android wallet at issuance |
Transactional email sub-processors
Resend, Inc. operates as a data processor for transactional email. It handles the recipient email address, recipient display name where present, email body (HTML and plain text), and sender address. It does not receive age verification data, wallet identifiers, attestations, or children’s data. It is used for low-volume transactional email tied to administrator and verifier onboarding; it is not used for marketing.
| Field | Detail |
|---|---|
| Data location | Primarily US-based infrastructure |
| GDPR compliance | Resend DPA with EU SCCs for transfers out of the EEA |
| Security certifications | SOC 2 Type II |
Authentication sub-processors
Silverhand Inc., operator of Logto, acts as a data processor for administrator authentication. It handles the administrator email address, Logto user identifier, organisation membership, role assignments, MFA factor metadata (TOTP seed reference, WebAuthn credential identifier, phone number for SMS OTP where enabled), session and refresh tokens, and sign-in events. It does not receive wallet data, age verification data, or children’s data. It provides OAuth 2.0 and OpenID Connect for the Provii administrator surface (admin-portal) and officer authentication in provii-issuer; end-user wallet flows do not interact with Logto.
| Field | Detail |
|---|---|
| Data location | Logto hosted tenant at auth.provii.app |
| GDPR compliance | Logto DPA with EU SCCs |
| Purpose | Administrator and officer identity provider |
Development tools (not production sub-processors of end-user personal data)
GitHub acts as a development tool rather than a production sub-processor of end-user personal data. It handles source code, CI/CD logs, build artefacts, and administrator sign-in events for the GitHub organisation. It does not receive age verification data, wallet identifiers, attestations, or children’s data. It is tracked under UC-070 and UC-144 (vendor and supply-chain management) rather than UC-147 (sub-processor management).
| Field | Detail |
|---|---|
| Data location | United States (GitHub.com) |
| GDPR compliance | GitHub Enterprise Cloud Data Protection Addendum with Standard Contractual Clauses |
| Security certifications | SOC 2 Type II |
| Data retention | Indefinite (version control) |
Package Registry Sub-Processors
npm Registry:
- Data Processed. Published packages (public)
- Data Location. United States
- Purpose. Public package distribution only
- No PII. Only package metadata and code
Crates.io:
- Data Processed. Published crates (public)
- Data Location. United States
- Purpose. Public package distribution only
- No PII. Only package metadata and code
Maven Central / Google Maven:
- Data Processed. Build-time dependencies only
- No Runtime Data. Used during development only
Cryptographic Key Management
Cloudflare Secrets Store:
- Data Stored. Master Encryption Keys (MEK), API keys, HMAC keys
- Encryption. Hardware Security Modules (HSMs)
- Access Control. Service bindings only (no human access)
- Rotation. Automated key rotation with versioning
Evidence: provii-verifier/wrangler.toml (Lines 126-164):
[[secrets_store_secrets]]
binding = "VERIFIER_MEK"
store_id = "<redacted: internal Cloudflare Secrets Store resource ID>"
secret_name = "VERIFIER_MEK"
[[secrets_store_secrets]]
binding = "VERIFIER_MEK_V1"
store_id = "<redacted: internal Cloudflare Secrets Store resource ID>"
secret_name = "VERIFIER_MEK_V1"
# Supports key rotation with multiple versions active
The Secrets Store entries above are Provii vendor-side keys. downpipes introduces exactly two vendor-side signing keys, neither of which protects customer data:
- downpipes Licence Signer — held in Cloudflare Secrets Store on the vendor-operated, fail-open control-plane; signs licence tokens, never gates backup or restore (Asset Register: CRYPTO-008).
- downpipes Update Signer — held offline by the operator and never deployed to any Worker; signs engine update artefacts for the signature-pinned
updates.downpipes.iochannel (Asset Register: CRYPTO-009).
No-custody key boundary (downpipes). The keys that protect downpipes backup contents — the customer’s break-glass, operational and archive-signer keys — are generated and held by the customer (guided in-browser key ceremony, printed recovery sheet, offline storage). They are not Maelstrom assets, never reach Cloudflare Secrets Store as a Maelstrom secret, and Maelstrom cannot decrypt, recover or rotate them — by design. Safeguarding them is a complementary user-entity control (CUEC) borne by the customer.
Control Mapping
UC-070: Vendor Management
Control Requirement: Maintain inventory of third-party vendors and assess their security posture.
Evidence:
- Vendor Inventory: Complete inventory documented above (Cloudflare, GitHub, npm, crates.io, etc.), spanning both platforms; the downpipes update channel runs on Cloudflare R2, already inventoried
- Security Assessment: SOC 2 / ISO 27001 certifications verified for critical vendors
- Contract Review: DPAs and security clauses documented in supplier-management.md
- Monitoring: Status pages monitored, security advisories reviewed
downpipes application: downpipes adds no new critical vendor. Its in-tenant engine and console run in the customer’s own Cloudflare account (the customer’s own infrastructure, not a Maelstrom vendor relationship); the only Maelstrom-operated downpipes surfaces — the control-plane and the signature-pinned update channel — run on Cloudflare, already inventoried above.
Reference: /trust/security/supplier-management.md
UC-144: Supply Chain Security Policy
Control Requirement: Implement supply chain security measures to prevent unauthorised modifications.
Evidence:
- SLSA Level 3: Hermetic builds, signed provenance, ephemeral environments
- Signed Commits: Sigstore keyless signing on all releases
- Provenance: in-toto attestations for all artefacts
- Transparency: Rekor transparency log entries
- downpipes update channel: signature-pinned, pull-only delivery (
updates.downpipes.io); the engine verifies each update against a pinned public key before applying, artefacts are signed by an offline-held Update Signer never deployed to any Worker, and a bad update is canary-rolled-back — preventing unauthorised modification of the in-tenant engine
Reference: /trust/developers/supply-chain-security.mdx
UC-145: Dependency Vulnerability Scanning
Control Requirement: Regularly scan dependencies for known vulnerabilities.
Evidence:
- Automated Scanning: Dependabot (weekly), cargo audit (CI/CD), npm audit (CI/CD)
- Daily Scans: Security-audit.yml runs daily at 2 AM UTC
- Trivy: Filesystem vulnerability scanning
- CodeQL: Static analysis for security issues
- Fail on High: Builds fail if high-severity vulnerabilities detected
Files:
provii-issuer/.github/workflows/security-audit.ymlprovii-agegate/.github/workflows/secure-build.yml(Lines 59-60)provii-verifier/.github/workflows/ci.yml(Lines 74-85)
UC-146: Licence Compliance
Control Requirement: Ensure third-party dependencies comply with licensing requirements.
Evidence:
- Licence Policy: Provii crates dual-licensed MIT OR Apache-2.0; Provii repositories under a per-repo mix (AGPL-3.0-only, Apache-2.0, MIT, some proprietary); downpipes engine/console/control-plane source-available under Elastic License v2, offline reader MIT (see Platform Outbound Licensing)
- Dependency Licences: Predominantly MIT/Apache-2.0 (permissive)
- GPL Denial: cargo deny explicitly rejects GPL-3.0, AGPL-3.0 in the Provii crate build
- Dependency Review: GitHub dependency review action checks licences on PRs
Files:
provii-crypto/Cargo.toml(Line 25)provii-issuer/.github/workflows/security-audit.yml(Lines 49-62, 74-76)
UC-147: Sub-Processor Management
Control Requirement: Maintain list of sub-processors and ensure GDPR compliance.
Evidence:
The canonical sub-processor roster is maintained at /trust/legal/sub-processors (version 1.1, effective 14 April 2026), which carries a completeness attestation and names the source-code sweep that backs it. As of that attestation, five sub-processors are engaged in production:
| # | Sub-processor | Purpose |
|---|---|---|
| 1 | Cloudflare, Inc. | Edge compute, KV, Durable Objects, R2, Workers Logs, Cloudflare managed challenge, Super Bot Fight Mode, WAF, Secrets Store, DNS |
| 2 | Apple Inc. (App Attest service) | Hardware-backed attestation for the iOS Provii wallet at issuance |
| 3 | Google LLC (Play Integrity API) | Device-integrity attestation for the Android Provii wallet at issuance |
| 4 | Resend, Inc. | Transactional email delivery for administrator and verifier onboarding |
| 5 | Silverhand Inc. (Logto) | OAuth 2.0 and OpenID Connect identity provider for the administrator surface and officer authentication in provii-issuer |
GitHub is a development tool rather than a production sub-processor for end-user personal data; it is covered separately under UC-070 and UC-144 as a supply chain vendor.
downpipes adds no entry to this roster. Under the no-custody model the engine and console run in the customer’s own Cloudflare account, under the customer’s own keys, so Maelstrom processes no downpipes customer data and engages no sub-processor for it. The two Maelstrom-operated downpipes surfaces — the fail-open control-plane and the signature-pinned update channel (updates.downpipes.io) — run on the Cloudflare infrastructure already listed at #1 and carry no customer keys or data, introducing no additional sub-processor and no international transfer of customer personal data. See Sub-Processors & Data Processing above and the Sub-Processors List downpipes scope note (canonical).
Stripe remains a planned payment processor, not live in production. It will be added to the canonical list when the billing integration lands, with 30 days’ advance notice to controllers as required under SCC Module 2 Clause 9(a) Option 2.
Supporting artefacts:
| Artefact | Location |
|---|---|
| Canonical sub-processor list | /trust/legal/sub-processors version 1.1 |
| Data Processing Addenda | Cloudflare master DPA with EU SCCs and UK IDTA, Apple Developer Program Schedule 2 DPA, Google Play Developer Data Processing and Security Terms, Resend DPA, Logto DPA |
| Data flows and retention | ROPA and per-sub-processor tables at /trust/legal/sub-processors |
| Transparency disclosures | Privacy Policy and DPIA |
| Change notification | 30 days’ advance notice mechanism documented at /trust/legal/sub-processors#notification-of-changes |
Reference: “Sub-Processors & Data Processing” section above (this document) and /trust/legal/sub-processors (canonical).
UC-148: Artefact Verification
Control Requirement: Provide mechanisms for users to verify integrity of distributed artefacts.
Evidence:
- Checksums: SHA256 checksums for all artefacts
- Signatures: Sigstore signatures with keyless signing
- SRI Hashes: Subresource Integrity hashes for browser bundles
- Provenance: SLSA provenance attestations (in-toto format)
- Verification Guide: Complete documentation for end users
- downpipes update artefacts: signature-verified against a pinned public key before the engine applies them (signed by the offline-held Update Signer); the MIT offline reader is built from a frozen public format specification, so customers can independently verify and restore archives from archive bytes plus their own key with no vendor in the loop
Files:
/trust/developers/artifact-verification.mdxprovii-agegate/.github/workflows/secure-build.yml(Lines 132-161, 196-236)
Gap Analysis
Current State: Strong
✅ Strengths:
- SLSA Level 3 supply chain security implemented
- Automated dependency scanning (Dependabot, cargo audit, npm audit)
- Keyless cryptographic signing with Sigstore
- Hermetic builds with locked dependencies
- provenance generation
- Licence compliance enforcement
- Vendor security assessment documented
- Sub-processor DPAs in place
- downpipes: signature-pinned, pull-only update channel with an offline-held Update Signer, canary-gated safe-apply and automatic rollback; no-custody architecture adds no sub-processor for customer data
⚠️ Areas for Enhancement:
- Branch Protection: Two-person review is not feasible for a sole operator and is accepted as a structural limitation; signed provenance and hermetic builds are in place as compensating controls
- SBOM Generation: Software Bill of Materials not yet automated
- VEX Documents: Vulnerability Exploitability eXchange not implemented
- Bit-for-bit Reproducibility: Not yet achieved (SOURCE_DATE_EPOCH not set)
- Dependency Review Policy: No formal policy document (relies on automated tools)
Recommendations
Short-term (1-3 months):
- Generate SBOMs during build process (CycloneDX or SPDX format)
- Document formal dependency review policy
Medium-term (3-6 months):
- Implement VEX documents for vulnerability disclosure
- Achieve bit-for-bit reproducible builds
- Automate licence compliance reporting
- Implement runtime attestation verification
Long-term (6-12 months):
- Migrate to hermetic container-based builds
- Implement automated vulnerability patching
- Establish vendor security reassessment schedule
- Create public transparency report for dependencies
Conclusion
Maelstrom AI has implemented third-party dependency management and supply chain security controls — across both platforms, Provii and downpipes — that meet or exceed industry best practices:
- Complete Vendor Inventory: All critical vendors documented with security assessments; downpipes adds no new critical vendor (its in-tenant engine and console run in the customer’s own Cloudflare account; the control-plane and update channel run on Cloudflare, already inventoried)
- Dependency Tracking: tracking across 4 ecosystems (Rust, JavaScript, Android, iOS)
- Supply Chain Security: SLSA Level 3 implementation (two-person review accepted as sole-operator limitation; compensating controls in place), complemented by the downpipes signature-pinned, pull-only update channel with an offline-held Update Signer
- Automated Scanning: Daily vulnerability scans, weekly dependency updates
- Cryptographic Signing: Keyless signing with Sigstore, non-falsifiable provenance
- Licence Compliance: Enforced via automated tools (cargo deny, dependency review); downpipes engine/console/control-plane source-available under Elastic License v2, offline reader MIT
- Sub-Processor Management: DPAs in place, data flows documented; downpipes is no-custody and adds no sub-processor for customer data
Controls UC-070, UC-144, UC-145, UC-146, UC-147, UC-148 are substantially addressed, with the enhancement opportunities noted above.
Document metadata:
| Field | Value |
|---|---|
| Document version | 1.1 (2026-06-19) |
| Platforms in scope | Provii (zero knowledge age verification) and downpipes (no-custody Cloudflare backup & disaster recovery) |
| Critical third-party vendors documented in this file | 6 (Cloudflare, GitHub, npm, Crates.io, CocoaPods, Maven Central / Google Maven); downpipes adds no new critical vendor (its control-plane and update channel run on Cloudflare, already inventoried) |
| Production sub-processors per canonical list | 5 (Cloudflare, Apple App Attest, Google Play Integrity, Resend, Logto/Silverhand), see /trust/legal/sub-processors v1.1; downpipes adds no sub-processor for customer data (no-custody) |
| Rust dependencies | Approximately 100 crates across provii-crypto, provii-verifier, provii-issuer, provii-mobile-sdk |
| JavaScript dependencies | 79 packages (provii-agegate) |
| Android dependencies | Approximately 40 libraries |
| iOS dependencies | 1 CocoaPod (YubiKit) |
| Evidence files analysed | More than 15 configuration files, 6 CI/CD workflows, 3 documentation files |
| Lines of evidence reviewed | More than 2,000 lines of configuration and workflow code |
| Next review date | 2026-11-21 (quarterly review schedule) |
Change history:
| Version | Date | Change |
|---|---|---|
| 1.0 | 2025-11-08 | Initial third-party & supply-chain evidence (Provii). |
| 1.1 | 2026-06-19 | downpipes added as second in-scope platform; the legacy backup worker retired in favour of self-hosted downpipes. Made the document cross-cutting across both platforms: added the downpipes signature-pinned update channel and offline-held Update Signer to supply-chain controls, the source-available (Elastic License v2) / MIT offline-reader outbound licensing, the downpipes vendor-side signing keys, and the no-custody position that Maelstrom adds no sub-processor for downpipes customer data. Australian/British spelling corrections applied (licence noun, artefact, unauthorised). |
End of Document