Do NOT report security vulnerabilities through public GitHub issues.
- Go to https://github.com/CHITTYAPPS/chittyfinance/security/advisories/new
- Click "Report a vulnerability"
- Include: description, reproduction steps, affected versions, impact
- Initial response: 24 hours
- Confirmation: 48 hours
- Critical fix: 7 days
- High priority fix: 14 days
We follow coordinated disclosure and will credit reporters unless anonymity is preferred.
| Version | Supported |
|---|---|
| Production (Cloudflare Workers) | Yes |
| Development (local Hono) | Best effort |
- Browser clients: KV-backed session cookies (
cf_session, 7-day TTL) - Service-to-service: Bearer token (
CHITTY_AUTH_SERVICE_TOKEN) - Password hashing: SHA-256 via Web Crypto API
- ChittyID SSO: OAuth 2.0 PKCE (primary auth path)
- Multi-tenant PostgreSQL (Neon) with tenant-scoped queries
- All storage methods enforce
tenantIdfiltering - Inter-tenant data access prevented at the storage abstraction layer
- All secrets delivered via Cloudflare Workers environment bindings
- 1Password is the cold source of truth
- No secrets in code, KV, or R2
- Pre-commit hooks scan for credential patterns
- OAuth state: HMAC-SHA256 signed tokens, 10-minute expiry, timing-safe verification
- Stripe webhooks: Signature verified via
STRIPE_WEBHOOK_SECRET - Mercury webhooks: Per-tenant HMAC-SHA256 (7 active registrations) — secrets stored encrypted per tenant, not as global env vars
- Wave webhooks: Endpoint deployed; per-tenant HMAC registration script pending (parity with Mercury pattern)
- Idempotency: All webhook events deduplicated via KV with 7-day TTL
- ChittyID SSO: OAuth 2.0 PKCE with code_verifier (PR #72) — primary browser auth path
Financial transaction classification follows a segregated trust model:
| Level | Role | Permissions |
|---|---|---|
| L0 | Ingest (webhook, CSV import) | Write to 9010 (suspense) only |
| L1 | AI/keyword classifier | Write suggested_coa_code only |
| L2 | Executor (owner/admin) | Set coa_code on unreconciled transactions |
| L3 | Auditor | Lock transactions (reconcile), review L2 classifications |
| L4 | Governance (auditor) | Modify Chart of Accounts |
Reconciled transactions are immutable. All classification changes logged to classification_audit with actor, trust level, old/new values, and reason.
- Decimal precision (12,2) for all monetary amounts
- Transaction amounts never stored as floating point
- Account numbers masked in logs
- No financial data cached in browser localStorage
- CSV imports validated and parsed server-side only
- SHA-256 deduplication hashes prevent duplicate ingestion
- External IDs prefixed by source (
tt-,hd-,az-) for traceability - Personal spend detection flags non-deductible purchases with
personalUsemetadata
| Integration | Auth Method | Data Flow |
|---|---|---|
| Mercury Bank | Direct webhooks (per-tenant HMAC) + ChittyConnect proxy (static egress IP) | Read-only account/transaction data |
| Wave Accounting | OAuth 2.0 + GraphQL | Read invoices/expenses |
| Stripe | API key + webhook signatures | Payment processing |
| OpenAI | API key | GPT-4o advice + GPT-4o-mini classification (no PII in prompts) |
| Cloudflare Email | DKIM/SPF + service auth | Inbound finance@chitty.cc |
| Service | Auth Method | Direction |
|---|---|---|
| ChittyAuth | Bearer service token | Inbound (token validation) |
| ChittyID | OAuth 2.0 PKCE | Outbound (SSO) |
| ChittyConnect | Service token | Outbound (Mercury proxy) |
| ChittyDiscovery | Service token | Outbound (self-register + heartbeat) |
| ChittySchema | Service token (advisory, fall-open) | Outbound (schema validation) |
| ChittyChronicle | Service token | Outbound (audit log writes) |
- CodeQL: Static analysis on every PR (27 alerts resolved 2026-03-24)
- Secret scanning: Working tree scanned for credential patterns
- Dependency audit:
npm audit --omit=dev --audit-level high(orpnpm auditif using pnpm-lock) - Workflow secret policy: Enforced via
check-workflow-secrets.sh - Bot detection: Governance workflow checks
user.type === 'Bot'(PR #95 hardening) - Script injection prevention: Workflow inputs passed via env vars, not template substitution (PR #95)
- Workers Builds: Deployed via Cloudflare's build pipeline (no self-hosted CI secrets); see issue #111 for current 0s-failure investigation
- Legacy session auth uses SHA-256, not PBKDF2/bcrypt — acceptable for Workers environment (no Node.js crypto); ChittyID SSO (OAuth 2.0 PKCE) is the primary auth path
- No application-level rate limiting — relies on Cloudflare's built-in DDoS protection; rate limiting on import/classification/webhook endpoints is an open follow-up
- Forensic tables use integer IDs — legacy schema (
shared/schema.ts), not yet migrated to UUID - ChittySchema client is fall-open — advisory only, never blocks writes (intentional: schema registry should not gate financial mutations)
- ChittyChronicle read-side blocked — write API works; cases/timeline/search endpoints return 404 (Worker only serves health + manifests). Audit writes succeed but cannot be queried via Chronicle UI.
- Email: security@chitty.cc
- GitHub Security Advisories: https://github.com/CHITTYAPPS/chittyfinance/security/advisories