Skip to main content

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:

AlgorithmPurposeLibrary
HMAC-SHA256Service auth, credential generationhmac, sha2
RS256Clerk JWT verificationjsonwebtoken
Ed25519OTA signature verificationed25519_compact
SHA-256File hash verificationsha2

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 Tenancy status, 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_variant
  • tests::test_tenancy_installer_denied_for_every_rpc_variant
  • tests::test_tenant_can_authorise_every_non_service_non_token_rpc
  • tests::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.json instead of null.
  • Audit what is stored in localStorage periodically; keep anything long-lived or high-value in lynx::store_credential() (Keychain / Keystore), not localStorage.
  • 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-Options
  • X-Content-Type-Options
  • Strict-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

  1. Penetration Testing: Regular third-party security assessments
  2. Dependency Scanning: Automated CVE detection in Cargo dependencies
  3. Secret Rotation: Periodic rotation of:
    • Service auth secrets
    • Credential generation seeds
    • OAuth client secrets
  4. Access Review: Periodic review of PM portfolio assignments

See Also