Sterling Security & Quality Audit Report

Comprehensive, evidence-based audit of all Sterling-built applications. Generated July 12, 2026.

Overall Risk Rating: HIGH

This audit identified 3 Critical, 5 High, 6 Medium, and 4 Low severity findings across 22+ Sterling-built applications. No evidence of active exploitation was found, but several findings represent immediate, exploitable vulnerabilities.

3
Critical
5
High
6
Medium
4
Low
SINGLE MOST IMPORTANT CONCERN: The OA Client Dashboards middleware has authentication completely disabled via code comment (line 18-20 of _middleware.js). Every API endpoint, including admin user management, client data, and team information, is publicly accessible to anyone on the internet with zero authentication. This is a live, exploitable vulnerability affecting a multi-tenant business application.

Critical Findings Summary

IDFindingApp
C-01OA Client Dashboards auth middleware entirely disabled — all routes publicoa-client-dashboards
C-02Command Center master API token hardcoded in CLAUDE.md and 30+ script/doc files on diskbrads-command-center
C-03NYO Football SMS endpoint has NO authentication — anyone can send SMS via Brad's Twilionyo-football-schedule

Application Inventory

22 wrangler.toml files found. Key applications with server-side logic (Functions/Workers) listed below.

AppTypeD1 DBAuthPublic URLStatus
brads-command-center Pages + Functions + D1 brain-dump-db d70dd166 PBKDF2 + SMS 2FA + master token brads-command-center.pages.dev Active
oa-client-dashboards Pages + Functions + D1 c2d686fc Cookie sessions (DISABLED) clients.outsourceaccess.com Auth Disabled
stevens-family-planner Pages + Functions + D1 stevens-family-planner-db 9ec1fd47 PBKDF2 + master token stevensfamilyplanner.com Active
stevens-family-planner-api Worker + D1 + AI Same as SFP 9ec1fd47 None (relies on SFP token) Worker route Wildcard CORS
core-forum-hub Pages + Functions + D1 fd48071a HMAC JWT + PBKDF2 + rate limiting coreforumhub.com Active
forum-update-builder Pages + Functions + D1 Shares brain-dump-db d70dd166 PBKDF2 + SMS 2FA + rate limiting forum-update-builder.pages.dev Active
lineup-tool-api Worker + D1 + Stripe 8456c065 JWT (HMAC-SHA256) + PBKDF2 Worker route (app.dugoutready.com) Active
nyo-football-schedule Pages + Functions None NONE nyo-football-schedule.pages.dev No Auth
sterling-social-approval Pages + Functions + KV None (uses KV) Query param token sterling-social-approval.pages.dev Token in URL
debs-swim-school-dashboard Pages + Functions + KV + D1 + AI eb4a1200 NONE debs-swim-school-dashboard.pages.dev No Auth
ai-mba-portal Pages + Functions + D1 91a07df1 PBKDF2 + sessions + rate limiting ai-mba-portal.pages.dev Active
dugoutready-survey Pages + Functions + D1 c449e0ca None (public form) dugoutready-survey.pages.dev By design
drill-save-worker Worker + D1 f388cbce + SFP DB UNVERIFIED Worker route Unverified
sterling-task-activation Pages + Functions + D1 ccdde90f Bearer token (prompt on load) sterling-task-activation.pages.dev Client-side token prompt
brads-brain-dump Pages + Functions + D1 Shares brain-dump-db d70dd166 Token via getAllowedOrigin brads-brain-dump.pages.dev (archived) Archived
oa-website-redesign Pages + Functions + D1 17eecb65 None (public voting) oa-website-redesign.pages.dev By design
debs-swim-school-referral Pages + Functions None None (public form) debs-swim-school-referral pages By design
dugout-ready-feedback Pages + Functions None Minimal dugout-ready-feedback.pages.dev Public form
oa-recruit-chat Pages + Functions None Origin-validated oa-recruit-chat.pages.dev Origin only

D1 Database Inventory

DB NameIDUsed By
brain-dump-dbd70dd166-2fb5-41c0-b3d2-efcf00c3abdebrads-command-center, brads-brain-dump, forum-update-builder
stevens-family-planner-db9ec1fd47-6e93-49c7-a35a-6e55c2e0ea36stevens-family-planner, stevens-family-planner-api, drill-save-worker
oa-client-dashboards DBc2d686fc-9347-4afa-a45f-6f5957a6e353oa-client-dashboards
core-forum-hub DBfd48071a-aa04-4536-9a67-b6a1c33317cecore-forum-hub
lineup-tool DB8456c065-24a5-414f-92e2-39d9c170a259lineup-tool-api
drill-library-dbf388cbce-8fa2-479a-af9d-390ada7ed940drill-save-worker
dugoutready-survey DBc449e0ca-89ae-40bb-a308-6012d388917cdugoutready-survey
ai-mba-portal DB91a07df1-1821-43fa-b216-7be691aed687ai-mba-portal
debs-swim-school DBeb4a1200-63dd-42ba-ba3d-a7e67a53c6aedebs-swim-school-dashboard
sterling-task-activation DBccdde90f-8e04-4d97-b6bb-721e550708b6sterling-task-activation
oa-website-redesign DB17eecb65-1879-4678-9a8b-e376b79f7c46oa-website-redesign

All Findings

IDCategorySeverityDescriptionEvidenceStatus
C-01AuthorizationCritical OA Client Dashboards middleware auth bypassed. Line 18: return await context.next(); before all auth logic. Every endpoint is public. oa-client-dashboards/functions/api/_middleware.js:18-20 Reported
C-02SecretsCritical Command Center master token a323a87f...ac08c hardcoded in CLAUDE.md line 987, plus 30+ script/doc/conversation files on disk. Anyone with filesystem access has full API access. CLAUDE.md:987, email-scan/process_emails.py:13, scripts/process-inbox-replies.js:23, scripts/finance-cashflow-sync.sh:8, skills/command-center-qa.md:16, etc. Reported
C-03AuthenticationCritical NYO Football SMS send endpoint has zero authentication. Any HTTP POST to /api/send-sms sends SMS via Brad's Twilio account. Attacker can send arbitrary SMS to any phone number, incurring charges. nyo-football-schedule/functions/api/send-sms.js:1-54 — no auth check anywhere Reported
H-01AuthorizationHigh Debs Swim School Dashboard has zero authentication on all 4 API endpoints (braindump, chat, schedule, tasks). Anyone can read/write Deb's data, trigger emails to clients, and save PDFs to her Google Drive. debs-swim-school-dashboard/functions/api/braindump.js — no auth check. Same for chat.js, schedule.js, tasks.js Reported
H-02CORSHigh Stevens Family Planner API Worker has CORS_ORIGIN = "*" hardcoded in wrangler.toml. Any website can make cross-origin requests to this API. stevens-family-planner-api/wrangler.toml:15CORS_ORIGIN = "*"; src/index.js:13'Access-Control-Allow-Origin': env.CORS_ORIGIN || '*' Reported
H-03Error HandlingHigh Multiple endpoints leak internal error details via e.message in HTTP responses. Leaks stack traces, API errors, and internal state to attackers. brads-command-center/functions/api/statement-scan.js:140detail: e.message; statement-detect.js:127; lineup-tool-api/src/index.js:542 Reported
H-04AuthenticationHigh SFP password minimum length is only 6 characters (Command Center requires 12). Weak password policy for a family app. stevens-family-planner/functions/api/auth.js:114-115password.length < 6 Reported
H-05AuthenticationHigh Rate limiting fails open. If the rate limit table check throws an error, the function returns false (not blocked), allowing unlimited login attempts. brads-command-center/functions/api/auth.js:115-117catch (e) { return false; } Reported
M-01SessionMedium Command Center session tokens stored in localStorage (when "Remember me" checked) are vulnerable to XSS theft. No HttpOnly flag possible for client-side tokens. brads-command-center/public/index.html:5100-5102 Reported
M-02AuthMedium Social Approval Dashboard passes auth token as URL query parameter (?token=...), which gets logged in server access logs, browser history, and Referer headers. sterling-social-approval/functions/api/posts/index.js:28-29url.searchParams.get('token') Reported
M-03SessionMedium Command Center sessions expire after 48 hours with no server-side session invalidation on password change for the current session (only other sessions are revoked). brads-command-center/functions/api/auth.js:258,313-314 Reported
M-04CORSMedium OA Client Dashboards CORS reflects the request Origin without validation (when auth is re-enabled, the middleware echoes url.origin directly). oa-client-dashboards/functions/api/_middleware.js:27'Access-Control-Allow-Origin': url.origin Reported
M-05AuthMedium Command Center auth error message inconsistency: line 275 says "at least 6 characters" but the actual check on line 274 enforces 12. Minor but suggests copy-paste error. brads-command-center/functions/api/auth.js:274-275 Reported
M-06HeadersMedium Command Center has no Content-Security-Policy header. Core Forum Hub has CSP but Command Center does not. brads-command-center/public/_headers — no CSP line Reported
L-01HeadersLow Workers (lineup-tool-api, drill-save-worker, sterling-scheduler-api) have no _headers file. Security headers only apply to Pages, not Workers, but no equivalent headers are set in Worker responses. No _headers in those directories; Worker response headers don't include X-Frame-Options, HSTS, etc. Reported
L-02ConfigLow Three D1 databases are shared across apps: brain-dump-db (3 apps), SFP DB (3 apps). If any one app is compromised, all data in shared DBs is exposed. wrangler.toml files cross-referenced Reported
L-03SessionLow No session revocation endpoint. Users cannot explicitly log out from other devices. Sessions expire naturally after 24-48 hours. No logout-all or device management functionality found in any app Reported
L-04CryptoLow Voicemail webhook signature verification uses SHA-1 HMAC. SHA-1 is deprecated though HMAC-SHA1 is not currently considered broken for this use. brads-command-center/functions/api/voicemail-webhook.js:30hash: 'SHA-1' Reported

Authentication Implementations

1. Brad's Command Center

Strongest auth implementation. PBKDF2-SHA256 (100K iterations), SMS 2FA via Twilio Verify, rate limiting, session tokens in D1.

Password Hashing (VERIFIED - Adequate)
// brads-command-center/functions/api/auth.js:18-28
async function hashPassword(password, salt) {
  const enc = new TextEncoder();
  const keyMaterial = await crypto.subtle.importKey(
    'raw', enc.encode(password), 'PBKDF2', false, ['deriveBits']
  );
  const bits = await crypto.subtle.deriveBits({
    name: 'PBKDF2',
    salt: enc.encode(salt),
    iterations: 100000,
    hash: 'SHA-256',
  }, keyMaterial, 256);
  return Array.from(new Uint8Array(bits))
    .map(b => b.toString(16).padStart(2, '0')).join('');
}
PBKDF2 with 100K iterations and random 16-byte salt. Adequate for current threat models. Consider Argon2id for future builds.
Rate Limiting (VERIFIED - Fails Open)
// brads-command-center/functions/api/auth.js:95-118
async function checkRateLimit(db, ip) {
  try {
    // ... rate limit logic ...
    return (row?.cnt || 0) >= 5; // blocked if 5+ attempts in 15 min
  } catch (e) {
    return false; // if rate limit table fails, don't block (but log it)
  }
}
FINDING H-05: Rate limiting fails open. If D1 is unavailable or the table query fails, catch returns false, allowing unlimited brute-force attempts. Should fail closed (return true to block).
Session Management (VERIFIED)
// Session creation: auth.js:541-542
const token = generateToken(); // 32 random bytes -> hex
const expiresAt = new Date(Date.now() + 48 * 60 * 60 * 1000).toISOString();
  • 32 bytes (256 bits) of CSPRNG entropy. Adequate.
  • 48-hour expiry. Reasonable for single-user admin panel.
  • Stored in D1, validated server-side on each request. Good.
  • On password change: other sessions revoked, current session kept. Correct.
  • No explicit logout endpoint found. Minor gap.

2. Stevens Family Planner

FINDING H-04: Minimum password length is only 6 characters. Command Center enforces 12. This is a family app that stores home addresses and personal data.
// stevens-family-planner/functions/api/auth.js:114-115
if (password.length < 6) {
  return jsonResponse({ error: 'Password must be at least 6 characters' }, 400);
}

3. OA Client Dashboards

FINDING C-01: The auth middleware exists, has full session validation, role-based access, and sliding window session extension. BUT it is entirely commented out. Every single API request bypasses auth.
// oa-client-dashboards/functions/api/_middleware.js:17-20
export async function onRequest(context) {
  // AUTH BYPASSED per Brad's directive (July 9, 2026) — all routes public
  return await context.next();
  /* ... 90 lines of auth code commented out ... */
}

4. Core Forum Hub

Uses HMAC-signed JWTs with SHA-256. Has rate limiting, login attempt tracking, and password reset flow. Appears well-implemented. Has CSP headers.

5. NYO Football Schedule

FINDING C-03: Zero authentication. The /api/send-sms POST endpoint directly calls the Twilio API to send SMS. No auth token, no session check, no API key validation. CORS is restricted to known origins, but CORS only blocks browser requests — any curl or script can call it directly.

6. Debs Swim School Dashboard

FINDING H-01: Zero authentication on all endpoints. The braindump, task list, schedule (which emails clients and saves to Google Drive), and AI chat endpoints are all publicly accessible. CORS is restricted but that only blocks browser-based cross-origin calls.

7. Lineup Tool API

JWT-based auth with HMAC-SHA256 signatures. PBKDF2 password hashing with 100K iterations. Stripe webhook signature verification implemented correctly with timestamp tolerance checking. CORS properly configured to specific origins in wrangler.toml.

Authorization & IDOR Analysis

OA Client Dashboards — TOTAL BYPASS

ALL endpoints are public. The middleware (line 18-20) does return await context.next(); before any auth check. This means:
  • GET /api/admin/users — Lists ALL users (email, name, role, status, last login). PUBLIC.
  • POST /api/admin/users — Creates new users including admin accounts. PUBLIC.
  • GET /api/admin/clients — Lists all client data. PUBLIC.
  • GET /api/admin/teams — Lists all team data. PUBLIC.
  • GET /api/dashboard — Returns dashboard data for any user. PUBLIC.
  • POST /api/auth/register — Open registration. Anyone can create an account. PUBLIC.
The admin endpoints check context.data?.user which is never populated (middleware doesn't set it), so the if (!user) return jsonResponse({ error: 'Not authenticated' }, 401) check in individual endpoint files IS triggered. The non-admin endpoints however have no such check and are fully open.

Correction to the above: Individual admin endpoints DO have if (!user) checks that return 401 because context.data.user is never set. So admin endpoints are inaccessible. But non-admin endpoints (dashboard, content, news, tickets, tools, va, hubspot-payments) have NO individual auth checks and are fully open.

Brad's Command Center — Single-User Model

Auth check happens at the start of each endpoint handler via authCheck(request, env). Returns 401 if unauthorized. No multi-tenancy, no IDOR risk by design (single user). However, the master token grants identical access to session-based access with no audit trail differentiation.

// brads-command-center/functions/api/_auth.js:21-52
export async function authCheck(request, env) {
  const auth = request.headers.get('Authorization');
  if (!auth || !auth.startsWith('Bearer ')) {
    return jsonResponse({ error: 'Unauthorized' }, 401);
  }
  const token = auth.slice(7);
  if (token === env.BRAIN_DUMP_TOKEN) {
    return null; // authorized — no user identity attached
  }
  // ... session check ...
}

Stevens Family Planner — Multi-User, Role-Based

Auth check returns user object including role. Some endpoints check user.role === 'admin' for privileged operations (create_user, delete_user, manage_user). The activities and restaurants endpoints do NOT filter by user_id, meaning any authenticated user can see/modify all records.

// stevens-family-planner/functions/api/activities.js:40-45
// ALL activities returned — no user_id filter
const result = await env.DB.prepare(
  'SELECT * FROM activities ORDER BY category, name'
).all();
return jsonResponse({ activities: result.results || [] });
This is likely by design (family-shared app), but there is no multi-family isolation. If the app were ever shared beyond the Stevens family, all data would be co-mingled.

Core Forum Hub — Proper Role-Based

JWT payload includes id, name, role (admin/member). Admin endpoints check role. Meeting endpoints reference the logged-in user's ID for voting, preventing impersonation. Best authorization implementation of all apps.

Lineup Tool API — Per-User Data Isolation

JWT includes userId. Team/player CRUD filters by user_id in D1 queries. IDOR protection appears adequate based on code review: queries use .bind(userId) consistently.

Injection & Input Validation

SQL Injection

All D1 queries across all apps use parameterized queries with .bind(). No string concatenation in SQL found. Zero instances of template literals in .prepare() calls. This is clean.

Evidence: grep -rn "\.prepare(\`" --include="*.js" --exclude-dir=node_modules returned zero matches. All queries use the pattern .prepare('SELECT ... WHERE x = ?').bind(value).

XSS

Multiple apps use innerHTML to render content, but most of this is admin-only content or server-provided data, not raw user input. Key observations:

The lack of Content-Security-Policy on most apps (M-06) means that even if XSS were achieved, there would be no CSP to limit the damage. Only Core Forum Hub has CSP.

Command Injection / SSRF

No exec(), eval(), or shell command invocations found in any Cloudflare Functions/Workers code. No SSRF vectors detected (no user-controlled URLs passed to fetch() in server-side code, except the Debs swim school schedule endpoint which fetches Google APIs only).

Input Validation

Input validation varies by app:

AppValidation LevelNotes
brads-command-centerGoodAuth validates types, lengths. Endpoints check required fields.
core-forum-hubGoodInput validation on auth, meeting data, votes.
dugoutready-surveyGoodValidates name length (200), email (254), JSON size (50KB).
lineup-tool-apiGoodJSON parse errors handled safely, required field checks.
debs-swim-school-dashboardMinimalChat validates message is string. Schedule has no input length limits on student names/emails.
nyo-football-scheduleNoneNo validation on to phone number format. Accepts any string and passes to Twilio.

Secrets & Configuration

FINDING C-02: Master API Token Exposure
The Command Center's BRAIN_DUMP_TOKEN (a323a87f73757758f37ed7df942eda23f137bd9115432ba36589cfbe7daac08c) appears in plaintext in 30+ files on the local filesystem. While the token itself is stored as a Cloudflare Worker Secret (not in wrangler.toml), its value has been pasted into scripts, skill files, conversation logs, and most critically, into CLAUDE.md which is version-controlled.

Files Containing the Master Token

CLAUDE.md:987
email-scan/process_emails.py:13
forum-update-builder/process-regen.sh:10
forum-update-builder/regen-processor.sh:10
scripts/process-inbox-replies.js:23
scripts/finance-cashflow-sync.sh:8
scripts/evening-ops-runner.md:85,452
scripts/evening-ops-verify.md:80
skills/cloudflare-pages-inventory-registration.md:14,43
skills/command-center-action-processor.md:15,22,54,62,71,84
skills/command-center-qa.md:16,28,233
conversations/*.md (20+ conversation logs)

Environment Variables by App

AppEnv Vars (in Cloudflare Secrets)In wrangler.toml?
brads-command-centerBRAIN_DUMP_TOKEN, TWILIO_SID, TWILIO_AUTH_TOKEN, TWILIO_VERIFY_SIDNo (correct)
core-forum-hubAPP_SECRET, RESEND_API_KEYNo (correct)
stevens-family-plannerSFP_TOKENNo (correct)
stevens-family-planner-apiGOOGLE_PLACES_API_KEYNo, but CORS_ORIGIN = "*" is in vars (H-02)
lineup-tool-apiJWT_SECRET, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRETNo (correct)
debs-swim-school-dashboardGOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REFRESH_TOKENUNVERIFIED — cannot confirm these are in CF secrets vs. vars
nyo-football-scheduleTWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_PHONE_NUMBERUNVERIFIED
sterling-social-approvalAUTH_TOKENUNVERIFIED
No API keys or tokens found hardcoded in any .js or .html source files that would be deployed to production. The sk-ant / sk-or-v1 grep returned zero matches. Secrets are properly stored as Cloudflare Worker Secrets or environment variables.

The risk is entirely in the local development environment files, not in deployed code.

Data & Privacy Analysis

Personal Data Inventory

AppData CollectedSensitivity
brads-command-centerUsername, password hash, phone number (for 2FA), tasks, financial uploads, email content, relationshipsHigh
oa-client-dashboardsEmail, full name, role, team assignments, client company data, VA assignmentsHigh (currently PUBLIC)
stevens-family-plannerUsername, display name, email, home address, photo URL, family activities, restaurant preferencesHigh
debs-swim-school-dashboardStudent names, student ages, parent/guardian names, guardian email addresses, lesson schedules, payment amountsCOPPA
core-forum-hubMember names, EO forum membership, meeting votes, feedbackMedium
lineup-tool-apiEmail, password hash, team rosters (player names), Stripe customer IDsMedium
dugoutready-surveyCoach name, email, survey responsesLow
nyo-football-schedulePhone numbers (via SMS send)Medium

COPPA Analysis

Debs Swim School Dashboard collects children's data:
  • Student 1 Name and Age (required fields)
  • Student 2 Name and Age (optional)
  • Parent/Guardian Name and Email

This app stores first names and ages of minor children. Under COPPA (Children's Online Privacy Protection Act), collecting personal information from children under 13 requires verifiable parental consent and a privacy policy. This app has no privacy policy, no parental consent mechanism, and no authentication (H-01). The data is stored in Cloudflare D1/KV and emailed to clients.

Mitigating factor: This is a small private swim school, not a commercial website directed at children. The operator (Deb) collects the info directly from parents in person. The COPPA applicability may be limited, but the lack of any access control on the stored data remains a concern.

Stevens Family Planner

SFP stores home_address in the users table. This is physical location data for Brad's family (including children Ella and Brayden). While the app requires authentication, the SFP API Worker has wildcard CORS (H-02), and the password minimum is only 6 characters (H-04).

Encryption

API & Abuse Protection

Rate Limiting

AppLogin Rate LimitAPI Rate LimitFails
brads-command-center5 attempts / 15 min per IPNoneOpen
core-forum-hub5 attempts / 15 min per IPNoneOpen
oa-client-dashboards5 attempts / 15 min per IP (when auth enabled)NoneN/A (auth disabled)
forum-update-builder5 attempts / 15 min per IPNoneOpen
ai-mba-portal5 attempts / 15 min (login + signup)NoneOpen
dugoutready-surveyN/A5 submissions / 15 min per IPClosed
lineup-tool-apiNone found in codeNoneN/A
All othersNoneNoneN/A
All apps with rate limiting use the same "fails open" pattern (H-05): if the rate limit DB query fails, the function returns false and allows the request through.

CORS Configuration

AppCORS PolicyAssessment
brads-command-centerLocked to https://brads-command-center.pages.devGood
core-forum-hubLocked to https://coreforumhub.comGood
stevens-family-plannerLocked to https://stevensfamilyplanner.comGood
stevens-family-planner-apiCORS_ORIGIN = "*" in wrangler.tomlWildcard
oa-client-dashboardsReflects url.origin (in commented auth block)Reflective
lineup-tool-apiConfigured to specific origins in wrangler.toml varsGood
sterling-social-approvalAllowlist + subdomain wildcardGood
debs-swim-school-dashboardLocked to production origin + subdomain wildcardGood
nyo-football-scheduleLocked to production origin + subdomain wildcardGood (but irrelevant for server-side calls)

Webhook Signature Verification

AppWebhookVerification
lineup-tool-apiStripe webhooksHMAC-SHA256 with 5-min timestamp tolerance + event dedup
brads-command-centerVoicemail webhookHMAC signature verification (SHA-1)

Bot/Abuse Protections

No CAPTCHA, no bot detection, no Web Application Firewall rules found on any app. Cloudflare's default bot mitigation applies to all Pages/Workers deployments, but no custom rules are configured (UNVERIFIED — would need Cloudflare dashboard access to confirm).

Dependencies & Supply Chain

Package.json Files Found

Most apps are zero-dependency (pure Cloudflare Pages Functions with no npm packages). Only a few have package.json:

AppDependenciesnpm audit Status
stevens-family-planner-apiWrangler dev dependency onlyUNVERIFIED (cannot run npm audit in container)
lineup-tool-apiWrangler dev dependency onlyUNVERIFIED
debs-swim-school-dashboardWrangler dev dependency onlyUNVERIFIED
dugoutready-chatbotUNVERIFIEDUNVERIFIED
drill-save-workerUNVERIFIEDUNVERIFIED
gchat-mcp-serverUNVERIFIEDUNVERIFIED
Supply chain risk is LOW. The vast majority of apps are zero-dependency, using only Cloudflare's native APIs (D1, KV, AI, R2). No third-party runtime dependencies were found in deployed code. All crypto is via Web Crypto API (native browser/worker API). No external auth libraries, no ORM layers, no middleware frameworks.

Hallucinated/Suspicious Packages

No evidence of hallucinated or suspicious npm packages. All package.json files contain only wrangler as a dev dependency, which is the official Cloudflare CLI.

Automated Scan Results

Hardcoded Secrets Scan

grep -rn "sk-ant\|sk-or-v1\|api[_-]key.*=.*['\"]" --include="*.js" --include="*.html" --include="*.toml" --exclude-dir=node_modules

Result: 1 match (false positive) — a Puppeteer script searching for API key elements on a page:
  scripts/cloudways-get-api-key.js:55 — querySelectorAll('code, pre, .api-key...')
No API keys or secrets found hardcoded in deployable source code.

SQL Injection Scan

grep -rn "\.prepare(\`\|\.prepare(.*\+\|\.prepare(.*\$\{" --include="*.js" --exclude-dir=node_modules

Result: 0 matches
All SQL queries use parameterized binding. No injection vectors found.

Wildcard CORS Scan

grep -rn "Access-Control-Allow-Origin" --include="*.js" --exclude-dir=node_modules

Results: 60+ matches analyzed. All use origin validation functions except:
  - stevens-family-planner-api/src/index.js:13 — env.CORS_ORIGIN || '*'
    wrangler.toml sets CORS_ORIGIN = "*" (FINDING H-02)

Error Message Leak Scan

grep -rn "err\.message\|e\.message\|error\.message" --include="*.js" --exclude-dir=node_modules | grep -i "response\|json\|return"

Findings:
  brads-command-center/functions/api/statement-scan.js:140 — detail: e.message
  brads-command-center/functions/api/statement-detect.js:127 — detail: e.message
  stevens-family-planner-api/src/index.js:203 — Places API error: ${placesData.error.message}
  lineup-tool-api/src/index.js:542 — session.error.message
  brads-brain-tabs/netlify/functions/sync-monday.js:80 — detail: e.message
FINDING H-03 confirmed. 5 instances of error message leakage to HTTP responses.

npm audit

Could not run npm audit in this environment. npm install would need to be run first in each project directory, which is outside the scope of this read-only audit.

Testing & Quality Assurance

ZERO automated tests exist across ALL Sterling-built applications.
AppUnit TestsIntegration TestsAuth TestsE2E TestsTest Coverage
brads-command-centerNoneNoneNoneNone0%
oa-client-dashboardsNoneNoneNoneNone0%
stevens-family-plannerNoneNoneNoneNone0%
core-forum-hubNoneNoneNoneNone0%
lineup-tool-apiNoneNoneNoneNone0%
All other appsNoneNoneNoneNone0%

No test runners (Jest, Vitest, Mocha, etc.) are configured in any package.json. No test scripts. No CI/CD pipeline configuration found (no .github/workflows, no wrangler-action configs). No test files of any kind exist in any application directory.

The only testing evidence is a dugoutready-tests/ directory with a package.json, which appears to be a Puppeteer-based manual test setup, not automated CI tests.

Impact: Auth bypass bugs (like C-01) would be caught immediately by even basic integration tests. The commented-out auth middleware would fail a test asserting that unauthenticated requests to /api/admin/users return 401.

OWASP ASVS Level 2 Assessment

Assessment against OWASP Application Security Verification Standard v4.0, Level 2 requirements. Evaluated against the primary apps (Command Center, OA Client Dashboards, SFP, Core Forum Hub, Lineup Tool).

V2: Authentication

ReqDescriptionStatusEvidence
2.1.1Password min length >= 12FailSFP: 6 chars. AI MBA: 8 chars. Only CC enforces 12.
2.1.2Password max length >= 128PassNo max length restrictions found in any app.
2.1.7Password checked against breach listsFailNo breach checking (haveibeenpwned, etc.) in any app.
2.1.9No password composition rulesPassNo uppercase/special char requirements. Length only.
2.2.1Anti-automation on authPassRate limiting present on login in CC, CFH, OA, FUB, AI MBA.
2.4.1Passwords stored with approved hashPassPBKDF2-SHA256, 100K iterations, random salt. All apps.
2.5.1Password reset does not reveal account existenceN/AOnly OA has password reset. Returns generic messages.
2.7.1OTP is time-limitedPassCC 2FA temp tokens expire after 10 minutes.
2.8.1Session tokens are cryptographically randomPass32 bytes CSPRNG via crypto.getRandomValues().

V3: Session Management

ReqDescriptionStatusEvidence
3.1.1Application never reveals session tokens in URLFailSterling Social Approval passes token as ?token= query param (M-02).
3.2.1New session on loginPassNew token generated on each successful login. All apps.
3.3.1Logout invalidates session server-sideFailCC/SFP: no logout endpoint found. Token just cleared from browser storage.
3.3.2Session timeoutPassCC: 48h. OA: 24h (sliding). Lineup: 30d (JWT exp).
3.4.1Cookie-based tokens use HttpOnly, Secure, SameSitePassOA login.js:65: HttpOnly, Secure, SameSite=Strict. CC uses Bearer tokens (not cookies).
3.7.1Re-authentication for sensitive operationsPassCC requires password to disable 2FA (auth.js:442-466).

V4: Access Control

ReqDescriptionStatusEvidence
4.1.1Access control enforced server-sideFailOA Client Dashboards: server-side auth disabled (C-01). NYO: no auth (C-03). Debs: no auth (H-01).
4.1.2Deny by defaultFail3 apps default to allow-all.
4.1.3Principle of least privilegeFailCC master token has full access with no audit differentiation from user sessions.
4.2.1IDOR/BOLA protectionPassLineup tool filters by user_id. SFP is single-family (no multi-tenant). CC is single-user.

V5: Validation, Sanitization, Encoding

ReqDescriptionStatusEvidence
5.1.3Input validation on all inputsFailNYO: no phone number format validation. Debs schedule: no input length limits.
5.2.1HTML sanitization for user contentFailinnerHTML used with AI responses (family-travel-chat). No DOMPurify or equivalent.
5.3.1SQL injection preventionPassAll D1 queries use parameterized .bind(). Zero string concatenation.
5.3.4Output encodingPassJSON.stringify for all API responses. No HTML rendering server-side.

Cannot Verify / Out of Visibility

The following items could not be verified during this source-code-only audit. They require access to the live Cloudflare dashboard, network testing, or runtime environment.

ItemWhy Not VerifiedRisk if Not Checked
Cloudflare Worker Secrets actually setCannot access Cloudflare dashboard from this environment. We can see env vars referenced in code but cannot confirm they are set as encrypted secrets vs. plaintext vars.High — if secrets are in plaintext vars, they appear in Wrangler logs and API responses.
Cloudflare WAF / Bot Protection rulesDashboard access required. Cannot confirm any custom WAF rules exist.Medium — default Cloudflare protection applies but custom rules would catch specific attack patterns.
D1 database actual contents / PII inventoryCannot query live D1 databases. Can only infer schema from CREATE TABLE statements in code.Medium — cannot confirm what data actually exists vs. what the schema allows.
npm audit resultsCannot run npm install / npm audit in this container environment. Package.json files exist but node_modules would need to be populated first.Low — most apps have zero runtime dependencies.
OA Client Dashboards live stateCannot confirm if auth is disabled on the DEPLOYED version vs. just in source code. Source shows disabled, but the deployed version might differ.Critical — if deployed matches source, all OA client data is public.
SSL/TLS configurationCannot perform TLS handshake testing from this environment.Low — Cloudflare enforces modern TLS by default.
DNS configuration / subdomain takeover risksCannot query DNS from container. Would need to check for dangling CNAME records.Medium — common attack vector on Cloudflare Pages with custom domains.
R2 bucket access policiesCannot query R2 ACLs. Sterling-media bucket is referenced for public CDN but cannot verify if other buckets are properly restricted.Medium — misconfigured R2 could expose uploaded files.
drill-save-worker auth implementationSource file not fully read during audit. Worker shares SFP database binding.Medium — if no auth, it's a second entry point to SFP data.
Actual deployment state of archived appsbrads-brain-dump, brads-brain-tabs marked as "archived" but source still exists. Cannot confirm if still receiving traffic.Low — if still deployed, old vulnerabilities may persist.

Prioritized Remediation Plan

Immediate (Do Today)

IDActionEffortImpact
C-01 Re-enable OA Client Dashboards auth middleware. Remove lines 18-20 (return await context.next();) and uncomment the auth block. If auth was disabled for a reason, add a TEMPORARY_AUTH_BYPASS environment variable instead of code commenting. 5 minutes Closes total auth bypass on multi-tenant business app
C-03 Add auth to NYO Football SMS endpoint. Require Bearer token or shared secret. Without this, anyone can send SMS at Brad's expense. 10 minutes Prevents Twilio abuse / bill-running attack
C-02 Rotate Command Center master token. Generate a new BRAIN_DUMP_TOKEN, update Cloudflare Worker Secret, update all scripts that reference the old token. Remove token from CLAUDE.md. 30 minutes Invalidates leaked token across 30+ files

This Week

IDActionEffortImpact
H-01 Add auth to Debs Swim School Dashboard. Simple shared password or PIN like Command Center uses. Protects student data (COPPA concern). 30 minutes Secures children's PII
H-02 Fix SFP API wildcard CORS. Change CORS_ORIGIN = "*" in wrangler.toml to CORS_ORIGIN = "https://stevensfamilyplanner.com". 2 minutes Prevents cross-origin attacks against family data
H-03 Remove e.message from HTTP responses. Replace detail: e.message with generic detail: 'Internal error' in all catch blocks. 15 minutes Stops information disclosure
H-04 Increase SFP password minimum to 12. Match Command Center's policy. 2 minutes Stronger passwords for family app
H-05 Make rate limiting fail closed. Change catch (e) { return false; } to catch (e) { return true; } in all rate limit functions. 5 minutes Prevents brute force during DB outages

Next Sprint

IDActionEffortImpact
M-01 Consider HttpOnly cookie-based sessions for Command Center instead of localStorage Bearer tokens. 2 hours Eliminates XSS token theft vector
M-02 Move Social Approval auth from URL query param to Authorization header. 30 minutes Prevents token leakage in logs/referer
M-04 Fix OA Client Dashboards CORS to use explicit allowlist instead of reflecting origin. 10 minutes Prevents cross-origin attacks when auth is re-enabled
M-05 Fix password change error message: "at least 6" should say "at least 12" to match actual check. 1 minute UX consistency
M-06 Add Content-Security-Policy to Command Center and all apps lacking CSP. 30 minutes Mitigates XSS impact
NEW Build basic automated tests. At minimum: (1) unauthenticated request to protected endpoint returns 401, (2) valid auth returns 200, (3) rate limit kicks in after 5 attempts. 2 hours Prevents regressions like C-01

Backlog

IDActionEffortImpact
L-01 Add security headers to Worker responses (not just Pages _headers files). 30 minutes Defense in depth
L-02 Evaluate separating shared D1 databases. Low priority unless apps are compromised. 2 hours Blast radius reduction
L-03 Add explicit logout/session revocation endpoints to all apps. 1 hour Session management hygiene
L-04 Upgrade voicemail webhook HMAC from SHA-1 to SHA-256. 5 minutes Cryptographic hygiene