Security Audit
This document provides a comprehensive security analysis of the Broadford Living codebase, covering authentication, data protection, and security practices.
Summary
The codebase demonstrates strong security practices overall, with proper use of parameterized queries, cryptographic operations, and authentication patterns. This audit identifies positive findings and areas for potential improvement.
Positive Security Findings
1. SQL Injection Prevention
All database queries use sqlx compile-time verified parameterized queries:
// Example from crates/bf_resident_db/src/operations/properties.rs
sqlx_d1::query!(
r#"
SELECT id, portfolio_id, address, unit, status
FROM properties
WHERE id = ?
"#,
property_id
)
.fetch_optional(conn)
.await?
Assessment: SQL injection risk is effectively mitigated through:
- Compile-time query verification via sqlx
- No string concatenation for SQL queries
- Consistent use of
?parameter binding
2. Token Encryption
OAuth tokens and sensitive credentials are encrypted at rest:
// Tokens stored in D1 are encrypted before storage
// Decryption happens only when needed for API calls
3. Cryptographic Implementation
Strong cryptographic libraries used throughout:
| Algorithm | Purpose | Library |
|---|---|---|
| HMAC-SHA256 | Service auth, credential generation | hmac, sha2 |
| RS256 | Clerk JWT verification | jsonwebtoken |
| Ed25519 | OTA signature verification | ed25519_compact |
| SHA-256 | File hash verification | sha2 |
4. JWT Validation
Comprehensive JWT validation with JWKS key rotation:
// crates/clerk-auth/src/lib.rs
// Token validation includes:
// - Signature verification
// - Expiration check (exp)
// - Issued-at check (iat)
// - Subject validation (sub)
// - Optional not-before check (nbf)
JWKS Caching:
- 5-minute TTL for key cache
- Automatic cache bust on key rotation
- Background refresh before expiration
5. Service-to-Service Authentication
Internal service communication uses short-lived tokens:
// crates/clerk-auth/src/service_auth.rs
pub struct ServiceAuthenticator {
// HMAC-SHA256 based token generation
// 5-minute token expiration - limits blast radius
// Request ID (jti) for replay protection
}
Security Features:
- Short 5-minute expiration limits compromised token impact
- JTI claim enables replay attack detection
- Service name validation prevents cross-service abuse
6. Deterministic Credential Generation
Service credentials use HMAC-based derivation:
// crates/bf_auth/src/credentials.rs
pub fn generate_email(
env: CredentialEnvironment,
service: Service,
unique_id: &str,
secret_seed: &[u8; 32],
) -> String {
// HMAC-SHA256 derivation
// Obfuscated output prevents reverse engineering
// Environment separation (dev/staging/prod)
}
7. Environment Separation
Clear separation between environments:
- Different credential seeds per environment
- Separate JWKS endpoints
- Environment-tagged credentials
8. Webhook Signature Verification
Both SmartThings and Yale webhooks are cryptographically verified:
// SmartThings: RSA-SHA256 (RFC-based signature)
// Yale: HMAC-SHA256
// 5-minute timestamp tolerance prevents replay
// Constant-time signature comparison
9. Role-Based Access Control
Well-designed RBAC with hierarchical roles:
// Role hierarchy: Admin > ItAdmin > PropertyManager > Installer > Tenant > Guest
// Property status-based access (vacant vs occupied)
// Portfolio-scoped PM access
Tenancy-period RPC invariant
A specific, stronger-than-RBAC guarantee applies inside the User Durable Object:
While a property is in
Tenancystatus, the tenant is the only authenticated role that can issue any RPC against the DO. Admins and installers are denied at the gate; PMs do not have direct DO access at all. Guests get a narrow, tenant-scoped subset.
The single deviation is a hand-curated allow-list of service-only RPCs — see is_service_only_request in crates/bf_user/src/permissions.rs. These RPCs require service-to-service auth (no user session); they cover device-token management, lifecycle/sync from bf_resident, signed webhook callbacks (SmartThings/Yale), cron jobs, and a few PM read endpoints that bf_resident proxies. Any other RPC issued under admin or installer auth during a tenancy is rejected.
The invariant is pinned by an exhaustive variant sweep in crates/bf_user/src/permissions.rs:
tests::test_tenancy_admin_denied_for_every_rpc_varianttests::test_tenancy_installer_denied_for_every_rpc_varianttests::test_tenant_can_authorise_every_non_service_non_token_rpctests::test_every_variant_is_classified_either_service_or_user
The sweep is exhaustive by construction. RpcRequest derives strum_macros::EnumDiscriminants, which generates a parallel unit enum RpcRequestKind with EnumIter. Each test iterates RpcRequestKind::iter() and runs the gate for every discriminant. A small placeholder_for_kind helper in the test module maps each discriminant to a minimal RpcRequest instance via an match over RpcRequestKind. Because that match is exhaustive, adding a new variant is a compile error until the contributor adds an arm — and the runtime sweep then automatically covers the new variant.
This means: if someone widens admin or installer access by accident in a future PR, the sweep fails before merge. If someone adds a new RPC variant, the test won't compile until they classify it.
See gdpr.md for the GDPR framing.
10. Mock Mode Compile-Time Removal
Mock authentication is excluded from production builds:
#[cfg(feature = "mock")]
// Mock code only included when feature flag enabled
// Production builds do not include mock bypass
11. Invite-Only Authentication
No public sign-ups - all users are invited via Clerk:
- Admin creates invitations
- Clerk handles email verification
- No self-registration vectors
12. Secure Environment Variable Handling
.env.local is properly gitignored:
- Secrets never committed to repository
- Production secrets managed via Cloudflare Secrets Manager
Areas for Improvement
Medium Priority
1. Rate Limiting
Current State: No rate limiting on API endpoints.
Risk: Potential for brute force or DoS attacks.
Recommendation: Implement rate limiting via:
- Tower middleware in Rust
- Cloudflare rate limiting rules
- Per-user and per-IP limits
2. CORS Configuration
Current State: Development CORS may be permissive.
Recommendation:
- Audit CORS settings for production
- Restrict
Access-Control-Allow-Origin - Validate allowed methods and headers
3. Error Message Information Disclosure
Current State: Some error messages may reveal internal details.
Recommendation:
- Generic error messages for client responses
- Detailed logging server-side only
- Sanitize stack traces from responses
4. Mobile WebView localStorage Relies on OS Sandboxing
Current State: The Tauri shell in crates/bf_mobile/ renders the Svelte
frontend from apps/mobile/, which caches a non-trivial amount of state in
the WebView's localStorage — including leased supplier credentials, door PIN
codes, guest data, property metadata, devices, push tokens, and user
preferences. None of this is encrypted at the application layer.
Risk: Confidentiality depends entirely on iOS / Android per-app sandboxing
(plus device-locked file protection). A jailbroken or rooted device, an XSS
inside the bundled JS, or an over-broad backup policy would expose the cache.
tauri.conf.json currently sets "csp": null, so there is no Content
Security Policy backstop against script injection in the WebView.
Recommendation:
- Document this dependency clearly (see Secret Management → WebView localStorage Cache).
- Configure a restrictive CSP in
tauri.conf.jsoninstead ofnull. - Audit what is stored in
localStorageperiodically; keep anything long-lived or high-value inlynx::store_credential()(Keychain / Keystore), notlocalStorage. - Exclude the WebView storage directory from device backups where feasible.
Low Priority
1. Security Headers
Consider adding additional security headers:
Content-Security-Policy(already have CSP hashes for OTA)X-Frame-OptionsX-Content-Type-OptionsStrict-Transport-Security
2. Audit Logging Enhancement
Current activity logging is good. Consider:
- Centralized security event logging
- Failed authentication attempt tracking
- Rate limit breach notifications
Security Architecture Summary
┌─────────────────────────────────────────────────────────────────────┐
│ Security Layers │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Network Layer │ │
│ │ • Cloudflare Edge (DDoS protection, WAF) │ │
│ │ • HTTPS only (TLS 1.3) │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Authentication Layer │ │
│ │ • Clerk JWT verification (RS256) │ │
│ │ • JWKS rotation with caching │ │
│ │ • Service-to-service HMAC tokens │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Authorization Layer │ │
│ │ • Role hierarchy (Admin → Guest) │ │
│ │ • Portfolio-scoped access │ │
│ │ • Property status checks │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Data Layer │ │
│ │ • Parameterized SQL queries (compile-time verified) │ │
│ │ • Token encryption at rest │ │
│ │ • Per-property data isolation (Durable Objects) │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ External Integration │ │
│ │ • Webhook signature verification │ │
│ │ • OAuth token management │ │
│ │ • Ed25519 OTA signature verification │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
Compliance Considerations
GDPR/Data Privacy
- Per-property data isolation via Durable Objects
- Move-out archival and deletion capabilities
- Guest data with time-limited access
Access Control Audit Trail
- Activity logging for PM actions
- Property status transition logging
- Credential creation logging
Security Testing Recommendations
- Penetration Testing: Regular third-party security assessments
- Dependency Scanning: Automated CVE detection in Cargo dependencies
- Secret Rotation: Periodic rotation of:
- Service auth secrets
- Credential generation seeds
- OAuth client secrets
- Access Review: Periodic review of PM portfolio assignments
See Also
- Secret Management - Credential security
- Authentication - Auth implementation
- Permissions - RBAC details
- Webhook Handling - Signature verification