Platform Reference11 min read

ADA CASA Assessment Controls & Codebase Mapping (`CASA-22465-11104`)

This document records all 48 verified security controls from the official TAC Security ESOF AppSec ADA CASA Assessment Report (Assessment ID: CASA-22465-11104, Status: 48 / 48 P...

ADA CASA Assessment Controls & Codebase Mapping (CASA-22465-11104)

This document records all 48 verified security controls from the official TAC Security ESOF AppSec ADA CASA Assessment Report (Assessment ID: CASA-22465-11104, Status: 48 / 48 PASS, covering CASA AL1 & AL2 requirements) and maps each control to the exact files, helpers, and architectural invariants that enforce it in this repository.

Mandatory Rule for Engineers & AI Coding Agents: Never remove, weaken, or bypass any control listed below. Automated guardrails in scripts/verify-security-guardrails.mjs and src/lib/__tests__/security-architecture-guardrails.test.ts continuously verify the structural invariants from this report.


Section 1: Authentication (1.1 – 1.3)

Control IDReport Sr. No.Requirement SummaryCodebase Implementation & Enforcement
1.1.1#37Authentication is resistant to brute force attacksDelegated to Firebase Authentication / Google Identity Platform (signInWithEmailAndPassword in src/lib/firebase/auth.ts) and verified server-side via Firebase Admin SDK (adminAuth.verifyIdToken in src/lib/server/auth.ts). Customer portal 6-digit OTP verification in /api/portal/auth/verify-code enforces strict attempt limits (attempts >= 5 invalidates code).
1.1.2#26System-generated initial passwords or activation codes shall be securely randomly generated and expire after a short periodPassword resets are delegated to Firebase Auth (sendPasswordResetEmail / confirmPasswordReset in src/lib/firebase/auth.ts). Portal 6-digit OTP codes use crypto.randomInt(100000, 999999) and expire after 10 minutes.
1.1.3#27Passwords shall be stored in a form that is resistant to offline attacksDelegated to Firebase Authentication (scrypt hashing managed by Google Identity Platform). Application never stores user account passwords in Firestore.
1.2.1#28Default credentials shall not be present on publicly exposed interfacesNo default, guest, or shared accounts exist on /login. All accounts require authenticated Firebase identity + verified tenant/subscription status.
1.3.1#29Out-of-band verifier shall expire in a reasonable timeframeFirebase Auth oobCode tokens expire automatically on Google's backend; portal OTP codes expire in 10 minutes.
1.3.2#30Out-of-band verifier shall only be used onceFirebase Auth oobCode is single-use (confirmPasswordReset returns auth/invalid-action-code on reuse); portal OTP codes are marked used: true atomically on first successful verification.
1.3.3#31Out-of-band verifier shall be securely randomFirebase Auth generates cryptographically random 44+ character oobCode tokens; portal OTP codes use Node crypto.randomInt.
1.3.4#32Out-of-band verifier shall be resistant to brute force attacksHigh-entropy Firebase oobCode tokens + rate-limited/attempt-capped OTP verification.

Section 2: Session Management (2.1 – 2.4)

Control IDReport Sr. No.Requirement SummaryCodebase Implementation & Enforcement
2.1.1#33Never reveal passwords, API keys, or session tokens in URL query stringsverifyAuthToken() only extracts tokens from the Authorization: Bearer <token> HTTP header. Passing ?access_token= or ?token= in the URL query string on standard API routes returns 401 Unauthorized. (Only specific <img src> / window.open print routes explicitly verify a short-lived ID token where browser headers cannot be set).
2.2.1#34Logout or session expiration shall invalidate all stateful session tokens, including refresh tokenssignOutUser() and signOutPortalUser() call revokeUserSessions(idToken) before calling signOut(auth), invoking adminAuth.revokeRefreshTokens(uid) server-side (see docs/SESSION_LOGOUT_SECURITY.md).
2.2.2#35Terminate all other active sessions (including refresh tokens) after a password change or resetFirebase Authentication invalidates existing sessions/refresh tokens upon confirmPasswordReset / password update.
2.2.3#36Non-revocable stateless authentication tokens must expire within 24 hoursFirebase ID tokens (RS256 JWTs) have a hard 1-hour (3600s) lifetime (exp - iat = 3600).
2.3.1#25Cookie-based session tokens shall have the Secure attribute set__session cookies set by Firebase App Hosting / application middleware enforce Secure.
2.3.2#38Cookie-based session tokens shall have the HttpOnly attribute set__session cookies enforce HttpOnly so client-side scripts (document.cookie) cannot read session cookies.
2.3.3#39Use session tokens rather than static API secrets and keysClient-to-server requests authenticate exclusively with short-lived Firebase Bearer ID tokens via fetchWithAuth(). Third-party OAuth integrations use short-lived Nango connect session tokens via /api/nango/session.
2.3.4#40Stateless session tokens shall use digital signatures (RS256) and reject tampering, alg:none, and key substitutionVerified via Firebase Admin SDK adminAuth.verifyIdToken(token) in src/lib/server/auth.ts, which enforces Google's RS256 public keys, issuer, audience, and expiration.
2.4.1#41Require a full valid login session or re-authentication before sensitive transactions or account modificationsSensitive account updates require recent authentication (reauthenticateWithCredential() with EmailAuthProvider.credential() when auth/requires-recent-login is raised).

Section 3: Access Control (3.1 – 3.3)

Control IDReport Sr. No.Requirement SummaryCodebase Implementation & Enforcement
3.1.1#42Enforce least-privilege access control rules on a trusted service layerAll /api/tenants/[tenantId]/** routes call verifyTenantAccess(request, tenantId). All Server Actions accepting a tenantId call verifyTenantAccessForAction(idToken, tenantId). Superadmin endpoints call verifyAdminRequest(request). Firestore rules in firestore.rules enforce canAccessTenant(tenantId) and deny direct client writes (allow write: if false) on sensitive collections.
3.1.2#43User/data attributes and policy information used by access controls cannot be manipulated by end usersStaff role and permissions live in tenants/{tenantId}/staff/{staffUid} and staffRegistry/{staffUid}, protected by owner checks (authResult.uid !== tenantId) in src/app/api/staff/route.ts and anti-self-escalation checks (SENSITIVE_SELF_FIELDS + staff_manage permission check) in src/app/api/tenants/[tenantId]/staff/[id]/route.ts (403 Forbidden).
3.1.3#44Access controls shall fail securely including when an exception occursverifyAuthToken, verifyTenantAccess, and verifyAdminRequest wrap token verification in try/catch and return 401/403 on any missing/malformed header or runtime exception without leaking stack traces.
3.1.4#45Protect sensitive resources against Insecure Direct Object Reference (IDOR) across CRUD operationsEvery tenant resource lives under tenants/{tenantId}/<subcollection>/{docId} and is queried/mutated only after verifyTenantAccess(request, tenantId) confirms the caller is either the shop owner (uid === tenantId) or a registered staff member (staffRegistry/{uid}.tenantId === tenantId). Cross-tenant IDs return 403 Forbidden.
3.2.1#13Securely validate redirect_uri and state parameters during OAuth 2.0 authorizationOAuth flows (brokered via Nango and Google Identity) validate redirect_uri against strict allowlists and bind requests to cryptographic state parameters.
3.2.2#48Implement only secure OAuth 2.0 flows (Authorization Code Flow with PKCE)OAuth integrations use Authorization Code Flow with PKCE (code_challenge / code_verifier with S256). Implicit and ROPC flows are not used.
3.3.1#2Application administrative interfaces shall use multi-factor authentication (MFA)Superadmin accounts require TOTP Multi-Factor Authentication via src/lib/firebase/mfa.ts, src/components/auth/TotpEnrollmentSetup.tsx, and src/components/auth/login-form.tsx (auth/multi-factor-auth-required), plus server-side superadmin checks in src/lib/server/admin-auth.ts.

Section 4: Cryptography (4.1)

Control IDReport Sr. No.Requirement SummaryCodebase Implementation & Enforcement
4.1.1#3Enforce TLS 1.2+ and secure cipher suites for all connectionsEnforced by Firebase App Hosting / Google Front End (TLS 1.2 and TLS 1.3 with AEAD cipher suites TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, and Strict-Transport-Security header in next.config.ts).
4.1.2#4Connections to and from the server shall use trusted TLS certificatesEnforced via Google Trust Services (WR2 / GTS Root R1) certificates on Firebase App Hosting and standard Node.js TLS certificate verification on outbound HTTPS calls (rejectUnauthorized is never disabled).
4.1.3#5No weak cryptography impacting confidentiality or integrity of confidential dataTenant credentials at rest (PSRestful subaccount tokens, SMTP passwords) are encrypted with AES-256-GCM in src/lib/utils/encryption.ts using a 256-bit key (CREDENTIAL_ENCRYPTION_KEY), 128-bit authentication tag, and fresh 16-byte crypto.randomBytes(16) IV per encryption (see docs/ENCRYPTION_KEY_MANAGEMENT.md). Secret comparisons use crypto.timingSafeEqual().
4.1.4#6Cryptographic modules fail securely and do not enable Padding Oracle attacksAuthenticated encryption (aes-256-gcm) verifies the 16-byte GCM authentication tag prior to returning plaintext (decipher.setAuthTag(authTag) in src/lib/utils/encryption.ts) and throws a generic error on tampering, preventing padding oracle side-channels.

Section 5: Input Validation & Output Encoding (5.1 – 5.2)

Control IDReport Sr. No.Requirement SummaryCodebase Implementation & Enforcement
5.1.1#7Protect against HTTP Parameter Pollution (HPP)URL query parameters are parsed via the standard WHATWG new URL(request.url).searchParams.get(...) API, which deterministically returns a single scalar string rather than an array or concatenated string.
5.1.2#8Limit URL redirects and forwards to allowlisted URLs or relative pathsPost-login redirects use getSafeRedirectUrl() to validate the redirect parameter: protocol-relative (//), absolute external (http:, https:), javascript:, data:, and backslash (\) URLs are rejected and default safely to /dashboard.
5.1.3#1Context-aware output escaping or sanitization protects against reflected, stored, and DOM-based XSSReact JSX auto-escapes rendered values by default; Content-Security-Policy (CSP) and security headers are configured in next.config.ts.
5.1.4#9 / #10Avoid eval() / dynamic code execution and template injectionNo user input is passed to eval(), new Function(), or server-side template evaluators.
5.1.5#11Prevent Server-Side Request Forgery (SSRF)All URL-fetching proxy routes (src/app/api/image-proxy/route.ts, src/app/api/gang-sheet/image-proxy/route.ts, and src/app/api/shipping/print-proxy/route.ts) MUST use fetchWithSsrfGuard(). fetchWithSsrfGuard resolves DNS records (dns.lookup(..., { all: true })), blocks RFC 1918 private IPs (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), loopback (127.0.0.0/8, ::1), link-local / cloud metadata (169.254.0.0/16 including 169.254.169.254), and re-validates every redirect hop (redirect: 'manual').
5.1.6#12Protect against XPath or XML injection attacksNo user-supplied XML is evaluated with XPath or external entity expansion (XXE).
5.1.7#14Protect against database (NoSQL/Firestore) injection attacksJSON payloads are validated for primitive types before Firestore queries, and all Firestore paths are scoped under verified tenants/{tenantId}/... references.
5.1.8#15Protect against OS command injectionNo user-controlled strings are interpolated into shell commands (exec/spawn). Vector rendering in src/lib/server/vector-renderer.ts uses argument arrays with temporary file paths generated server-side.
5.1.9#16Protect against Local File Inclusion (LFI) and Remote File Inclusion (RFI)Dynamic routes treat path parameters strictly as database identifiers or return Next.js 404s; no user input is passed to fs.readFile without strict path confinement.
5.1.10#46Enforce anti-CSRF protection on authenticated functionalityAll authenticated API mutations require a custom Authorization: Bearer <idToken> header (injected by fetchWithAuth()) and JSON Content-Type: application/json, which browsers block cross-origin without CORS preflight approval.
5.2.1#17Protect against malicious file uploads (type restriction, size limit, no direct execution)src/app/api/upload-public-image/route.ts and src/app/api/gang-sheet/upload/route.ts enforce a 50MB limit, block executable MIME types and extensions (html, js, php, sh, exe, etc.), and set contentDisposition: 'attachment' on SVG/XML uploads so browsers never execute them inline (see docs/FILE_UPLOAD_SECURITY.md).

Section 6: Configuration, Dependencies & Secrets (6.1 – 6.7)

Control IDReport Sr. No.Requirement SummaryCodebase Implementation & Enforcement
6.1.1#18Only use software components without known exploitable vulnerabilitiesDependencies in package.json are patched against known CVEs (firebase-admin, next, nodemailer, etc.).
6.2.1#19Disable debug modes and stack trace exposure in production environmentsNext.js production builds return generic JSON/HTML error responses without exposing internal stack traces or source maps.
6.3.1#20The Origin header shall not be used for authentication or access control decisionsAuthentication and authorization rely exclusively on verified cryptographic tokens (verifyAuthToken / verifyTenantAccess), never on spoofable Origin or Referer headers.
6.4.1#21The application shall not be susceptible to subdomain takeoversWildcard and custom domains are managed through Firebase App Hosting with active TLS certificates and tenant subdomain routing in src/proxy.ts.
6.5.1#22Never log credentials, session tokens, or payment card details (PAN/CVV)Card payments are tokenized client-side via Stripe Elements (js.stripe.com) or Square Web Payments SDK; raw card numbers never touch the application server. Server logs redact secrets via sanitizeCredentials() and maskCredential().
6.6.1#23Browser storage is securely cleared during logoutsignOutUser(), signOutPortalUser(), and TenantProvider clear sessionStorage (effectiveTenantId, tenantData, isStaff, permissions) and sensitive localStorage keys (last_tenant_brand) upon sign-out.
6.7.1#24Securely store access tokens, API keys, and server-side secretsPlatform secrets are managed in Google Cloud Secret Manager and injected via apphosting.yaml; tenant OAuth tokens are stored in Nango's vault (only connectionId is in Firestore); tenant API keys/SMTP credentials are encrypted at rest with AES-256-GCM (see docs/SECRETS_ACCESS_CONTROL.md).
6.7.2#47Directory browsing shall be disabledNext.js App Router serves only explicitly defined routes and static assets in public/; directory listing requests return 404 Not Found.
Interactive Setup Support

Have a question about this feature?

Log into your Print Life dashboard anytime and click the Shop Co-Pilot button. You can ask anything from margin math to work center capacity, and the AI wizard will guide you through step-by-step.