You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Deed Shield — Security & Production Readiness Checklist
This document tracks the security posture of the Deed Shield API.
Each item is either ✅ (verified in-repo), 🔒 (enforced by code), or 📋 (requires infra/ops verification).
1. Secrets & Repository Hygiene
#
Requirement
Status
Evidence
1.1
No .env, .env.local, or secret files in git history
See .gitignore — covers **/.env, .env.local, attestations.sqlite.
1.3
.env.example provided with placeholder values (no real secrets)
✅
apps/api/.env.example — contains only empty strings and localhost URLs.
1.4
Developer setup guide documents how to obtain secrets
✅
apps/api/SETUP.md — references team leads / secrets manager.
1.5
GitHub secret scanning enabled
⚠️
Requires GitHub Advanced Security (public repos or Enterprise plan). Dependabot alerts are enabled. For private repos on free/team plan, use git-secrets or trufflehog as a pre-commit hook instead.
1.6
Rotate any secrets that were ever committed
📋
All API keys, DB passwords, and private keys that existed in .env.local or apps/api/.env prior to the scrub must be rotated. Treat them as compromised.
2. Database Security
#
Requirement
Status
Evidence
2.1
Schema uses postgresql provider
✅
apps/api/prisma/schema.prisma line 6.
2.2
TLS enforced on DB connections in production
🔒
server.ts startup guard rejects DATABASE_URL without sslmode=require|verify-full|verify-ca when NODE_ENV=production.
2.3
Encryption at rest on DB volume
📋
Must be verified on the hosting provider (Render, AWS RDS, Supabase, etc.). Capture evidence using docs/ops/db-security-evidence.md and store the exported proof in private compliance storage.
2.4
Separate DB credentials per environment
📋
Production, staging, and development must use distinct credentials with least-privilege grants.
2.5
DB user has minimal required permissions
📋
Production DB user should have SELECT, INSERT, UPDATE only — no DROP, CREATE, or superuser. Prisma Migrate should use a separate privileged user.
2.6
Connection pooling configured
📋
Use PgBouncer or Prisma Accelerate for connection management in production.
3. API Trust Boundaries
#
Requirement
Status
Evidence
3.1
All endpoints require x-api-key auth
✅
Every route except /health and /synthetic uses requireOrg().
3.2
Single auth chokepoint (requireOrg)
✅
apps/api/src/utils/auth.ts — all routes funnel through this.
3.3
Organization ownership enforced on reads
✅
GET /receipts, GET /receipt/:id, GET /receipt/:id/pdf all check organizationId.
3.4
Cross-tenant isolation tested
✅
v2-integration.test.ts — Org B cannot see/access Org A data (403).
3.5
Per-org metering via RequestLog.organizationId
✅
Verified by test: RequestLog entries have organizationId populated.
3.6
Rate limiting enabled
✅
@fastify/rate-limit configured.
3.7
Security headers (Helmet)
✅
@fastify/helmet configured.
3.8
Request body size limits
✅
bodyLimit: 5242880 (5 MB) on /verify.
3.9
Input validation (Zod + JSON Schema)
✅
verifyRouteSchema + Zod on ATTOM endpoint.
4. Cryptographic Integrity
#
Requirement
Status
Evidence
4.1
Keccak-256 for document hashing
✅
keccak256Buffer from @trustsignal/core.
4.2
Receipt hash verification
✅
POST /receipt/:id/verify recomputes hash.
4.3
JWT receipts have expiration
✅
Enforced in core receipt builder.
4.4
Private keys never in code or config files
✅
Only via PRIVATE_KEY env var, never imported directly.
5. Dependency Security
#
Requirement
Status
Evidence
5.1
npm audit clean
✅
0 vulnerabilities in production and dev dependencies.
5.2
Dependabot alerts enabled
✅
Enabled via GitHub API.
5.3
Known alerts triaged
✅
Alert #45 (ajv ReDoS) dismissed — dev-only transitive dep of ESLint, production uses patched ajv@8.18.0 via Fastify.
5.4
No lint errors in codebase
✅
All ESLint errors resolved. Only remaining notice is Prisma v7 migration advisory (informational).
6. Pre-Deployment Verification Commands
# 1. Verify no secrets in git history
git rev-list --all | xargs -I{} git ls-tree -r {} --name-only | grep -E '\.env$|\.env\.local$|\.sqlite$'| sort -u
# Expected: empty output (or only .env.example / schema.sqlite.sql)# 2. Run full test suitecd apps/api && npm test# 3. Verify DATABASE_URL has TLSecho$DATABASE_URL| grep -q 'sslmode='&&echo"TLS configured"||echo"WARNING: No sslmode"# 4. Check npm audit
npm audit --production
# 5. Capture DB security evidence bundle (staging/prod)
DATABASE_URL="$DATABASE_URL" npm run evidence:db -- --environment staging --db-instance-id <rds-instance-id>
7. Items Requiring Out-of-Repo Action
These cannot be verified in code and require manual confirmation:
#
Action
Who
Notes
7.1
Rotate ATTOM_API_KEY
Ops
Was in .env.local — generate new key in ATTOM dashboard
7.2
Rotate OPENAI_API_KEY
Ops
Was in .env.local — revoke old key in OpenAI dashboard
7.3
Rotate PRIVATE_KEY
Ops
Ethereum wallet key — generate new wallet, transfer any assets, update PRIVATE_KEY env var
7.4
Rotate DATABASE_URL
Ops
Change DB password if it was in any committed file
7.5
DB encryption at rest
Infra
Confirm with hosting provider (Render/Supabase/RDS all support this)
7.6
DB TLS certificate
Infra
Ensure CA cert is valid, not self-signed, for production
7.7
Separate staging/prod credentials
Ops
Create distinct DB users and API keys per environment
7.8
Pre-commit secret scanning
Dev
Install git-secrets or trufflehog as pre-commit hook (since GitHub secret scanning requires Enterprise)
7.A Rotation Evidence And Cadence
Rotation policy:
rotate exposed or suspected-exposed secrets immediately
rotate standing secrets at least every 90 days unless a stricter provider or customer obligation applies
record the operator, timestamp, and validation outcome for every rotation event
Store rotation evidence in:
Vanta
private compliance storage
a private audit repository
Recommended evidence bundle for each rotated secret:
Secret
Cadence
Evidence Required
Evidence Location
ATTOM_API_KEY
Immediate if exposed, otherwise every 90 days
provider rotation log, redacted screenshot, post-rotation smoke test result
Vanta or private audit repository
OPENAI_API_KEY
Immediate if exposed, otherwise every 90 days
provider rotation log, redacted screenshot, post-rotation smoke test result
Vanta or private audit repository
PRIVATE_KEY
Immediate if exposed, otherwise on key-management schedule