-
Notifications
You must be signed in to change notification settings - Fork 60
Open
Labels
Description
Audit timestamp: 2026-03-25 23:02
Git state: develop @ 78f620090 — pulled from origin/develop before this run
Latest commits:
- 78f6200 fix: regenerate Windows ICO with all standard sizes (fix: regenerate Windows ICO with all standard sizes (16-256px) #1353)
- facfc2b [fix] fix desktop companion header glass bleed ([fix] fix desktop companion header glass bleed #1346)
- e09abae fix: add missing onboarding preview tts helper (fix: add missing onboarding preview tts helper #1341)
Audit method: Fresh dev environment startup + API live-testing (localhost:31337) + UI audit (localhost:2138) + static code analysis
App state: API :31337 ✅ Running — Dashboard UI :2138 ✅ Running
Environment startup: PID 25004 — API ready in ~15s — UI ready in ~15s
Runtime Environment
| Service | Port | Status | Startup Time |
|---|---|---|---|
| API + WebSocket | 31337 | ✅ Running | ~15s |
| Dashboard UI (Vite) | 2138 | ✅ Running | ~15s |
Environment Startup Log
Database shutting-down error observed during startup:
Unhandled rejection: Error: Database is shutting down - operation rejected
at withDatabase (@elizaos/plugin-sql/dist/node/index.node.js:6841:25)
Server recovered after this error. Migrations completed successfully. UI stuck on "INITIALIZING ENTITY" indefinitely.
Issue Index
| ID | Severity | Title |
|---|---|---|
| UX-1 | P0 | UI stuck on "INITIALIZING ENTITY" — chat unusable |
| SEC-1 | P1 | /api/config returns cloud API key without authentication |
| SEC-2 | P1 | /api/database/tables returns full DB schema without authentication |
| SEC-3 | P2 | /api/permissions leaks platform info (_shellEnabled) without auth |
| UX-2 | P2 | No loading timeout or error recovery — infinite spinner |
| UX-3 | P2 | Database "shutting down" unhandled rejection on startup |
| A11Y-1 | P2 | Header icon buttons (Companion/Character/Native mode) lack accessible labels |
| A11Y-2 | P3 | Loading spinner has no aria-live region for screen readers |
| UX-4 | P3 | Chat input enabled while entity still initializing — messages would fail silently |
Per-Persona Findings
1. Alex (Solo Dev) — ⭐⭐⭐ (3/5)
Likes:
- CLI and config system well-structured (
~/.milady/milady.json) - Plugin auto-enable and NODE_PATH resolution documented and functional
- Multiple token header formats supported (Bearer, X-Eliza-Token, X-Milady-Token, X-Api-Key, X-Api-Token)
Dislikes:
- Entity initialization hangs indefinitely in dev mode — blocks iterating on agent config
- Database "shutting down" error appears in logs with no user-facing explanation
/api/agentsreturns 404 — unclear how to list agents via API
Issues:
- [UX-1/P0] UI stuck on "INITIALIZING ENTITY" —
apps/app/src/main.tsxlaunches companion view, but the entity init call never resolves. Observed live: spinner and "INITIALIZING ENTITY" text persist indefinitely. - [UX-3/P2] Database "shutting down" unhandled rejection in
@elizaos/plugin-sql— observed in/tmp/milady-audit-dev.logline withwithDatabaseatindex.node.js:6841. Does not crash server but may cause entity init failures.
2. Maria (Non-Technical Creator) — ⭐⭐ (2/5)
Likes:
- Clean, dark-themed UI with clear "New Chat" and "Voice" buttons
- Language selector visible in header (currently EN with flag)
- Cloud credits balance ($18.9) visible at a glance
Dislikes:
- Cannot get past loading screen — "INITIALIZING ENTITY" blocks all interaction
- No onboarding wizard visible despite
onboardingComplete: truein config — unclear how a new user would create their first agent - Chat input appears clickable during loading but would fail silently
Issues:
- [UX-1/P0] Same entity initialization hang — Maria cannot interact at all
- [UX-2/P2] No timeout, retry button, or error message after loading stalls — infinite spinner with no escape hatch. Loading component needs a timeout (e.g. 30s) with actionable error message.
- [UX-4/P3] Chat input
textbox "Chat message"is enabled during loading — confirmed via accessibility tree (ref_26has nodisabledattribute)
3. Jordan (DevOps Engineer) — ⭐⭐⭐ (3/5)
Likes:
- Port configuration well-documented with env overrides (MILADY_API_PORT, MILADY_PORT, etc.)
ELIZA_DEV_ONCHAIN=0correctly disables Foundry/Anvil when not installed- Dev server starts cleanly with PID trackable for process management
Dislikes:
- No health check endpoint —
/api/agentsreturns 404, root returns{"error":"Not found"} - Database shutdown error in startup logs would trigger alerts in monitoring
- No readiness probe pattern for container orchestration
Issues:
- [UX-3/P2] Database "shutting down" unhandled rejection — would cause false-positive alerts in production monitoring. Needs proper error handling in
@elizaos/plugin-sql.
4. Sam (Crypto-Native Power User) — ⭐⭐⭐ (3/5)
Likes:
- Wallet key endpoint (
/api/wallet/keys) properly gated behindensureCompatSensitiveRouteAuthorized()atpackages/app-core/src/api/server.ts:2419 - Wallet keys endpoint disabled after onboarding via temporal check (line 2428-2432)
- OS keystore integration (
/api/wallet/os-store) requires sensitive route auth
Dislikes:
/api/walletreturns 404 — no wallet status endpoint available/api/wallet/exportreturns 404 — wallet export flow unclear from API perspective
Issues:
- No new wallet-specific issues beyond the general P0 loading hang.
5. Priya (Enterprise Evaluator) — ⭐⭐ (2/5)
Likes:
- Timing-safe token comparison using
crypto.timingSafeEqual()inpackages/app-core/src/api/auth.ts:36-41 - Security headers properly set:
X-Content-Type-Options: nosniff,X-Frame-Options: DENY,X-XSS-Protection: 1; mode=blockatpackages/agent/src/api/server.ts:6358-6361 - Auth gate applied BEFORE CORS processing to prevent DNS rebinding (
packages/agent/src/api/server.ts:5821-5824) - Sensitive routes properly wrapped with
ensureCompatSensitiveRouteAuthorized()
Dislikes:
/api/configreturns full configuration including cloud API key (eliza_baaf6c...) without any auth — confirmed via live curl returning HTTP 200 with full config JSON/api/database/tablesreturns full database schema (all tables, columns, types) without auth — full schema enumeration/api/permissionsreturns{"_platform":"darwin","_shellEnabled":true}without auth — platform info disclosure
Issues:
- [SEC-1/P1]
/api/configunauthenticated — returns cloud API key, agent config, plugin settings. Confirmed atpackages/app-core/src/api/server.ts:3193. The route handler does not call any auth middleware. An attacker on the same network could steal the cloud API key. - [SEC-2/P1]
/api/database/tablesunauthenticated — returns full DB schema with all table names, column types, and constraints. Confirmed live: 24 tables exposed includingagents,memories,embeddings,pairing_requests. - [SEC-3/P2]
/api/permissionsunauthenticated — exposes_platform(darwin) and_shellEnabled(true). Useful for targeted attacks.
6. Chen (Plugin Developer) — ⭐⭐⭐ (3/5)
Likes:
- NODE_PATH correctly set in three required locations per CLAUDE.md
bun run setup:eliza-workspacefor local Eliza development documented- Plugin auto-enable system with config schemas in
packages/app-core/src/config/ - 78 skills loaded successfully per startup logs
Dislikes:
- Plugin load failures are silent — NODE_PATH setup could fail with unclear errors (
packages/agent/src/runtime/eliza.ts:155-188) /api/pluginsendpoint is open (no auth) — leaks installed plugin list
Issues:
- No new plugin-specific issues beyond general findings.
7. Riley (Mobile-First User) — ⭐⭐ (2/5)
Likes:
- Chat input and send button are appropriately sized for touch targets
- Bottom-anchored message bar pattern is mobile-friendly
Dislikes:
- Header bar does not collapse at narrow viewports — all 7+ buttons remain in a single row
- No hamburger menu or responsive navigation pattern detected
- "INITIALIZING ENTITY" loading state blocks all mobile interaction
Issues:
- [UX-1/P0] Loading hang blocks all mobile interaction
- [UX-2/P2] No responsive breakpoint for header navigation — buttons would overflow on small screens
8. Taylor (Accessibility User) — ⭐⭐ (2/5)
Likes:
- Chat input has proper
textboxrole withplaceholder="Type a message..."label - Buttons have text content for screen readers (e.g. "New Chat", "Agent voice on", "Toggle theme")
- Page has
banner,complementary, andregionlandmarks for navigation
Dislikes:
- Mode toggle buttons (Companion/Character Edit/Native) identified as generic
buttonwith text but wrapped in ageneric "Switch shell view"container with norole="tablist"oraria-selected - Loading state has no
aria-live="polite"region — screen reader won't announce "INITIALIZING ENTITY" status changes - File upload button (
ref_24) has no accessible label — justbuttonwithtype="file"
Issues:
- [A11Y-1/P2] Mode toggle lacks ARIA tab pattern —
ref_4,ref_5,ref_6are buttons insideref_2(generic div). Should userole="tablist"witharia-selectedon the active tab. - [A11Y-2/P3] Loading spinner lacks
aria-live— the "LOADING..." / "INITIALIZING ENTITY" text is not in anaria-liveregion so screen readers won't announce state changes. - File upload button (
ref_24) has no label — needsaria-label="Attach file"or similar.
9. Jamie (Multi-Platform User) — ⭐⭐⭐ (3/5)
Likes:
- Connectors endpoint (
/api/connectors) properly returns connector status - Platform connector architecture in
packages/app-core/src/connectors/ - WebSocket broadcast callback wired for real-time sync per startup logs
Dislikes:
- No connectors currently enabled (
/api/connectorsreturns{"connectors":{}}) — unclear how to enable Telegram/Discord from UI - Loading hang prevents testing multi-platform chat sync
Issues:
- No new platform-specific issues beyond general findings.
10. Casey (First-Time Visitor) — ⭐ (1/5)
Likes:
- Dark theme is visually appealing
- Layout is clean and uncluttered
Dislikes:
- App immediately goes to companion view with infinite loading spinner — zero context for what's happening
- No welcome message, tutorial, or explanation of what Milady is
- "INITIALIZING ENTITY" provides no actionable information to a new user
- Chat input is enabled but nonfunctional during loading — sending a message would fail with no feedback
- No error recovery path — no "Try Again" button, no settings link, no help text
Issues:
- [UX-1/P0] Critical first impression failure — new user sees infinite spinner with no escape
- [UX-2/P2] No timeout or error recovery UI
- [UX-4/P3] Misleading enabled chat input during loading
Confirmed Non-Issues
| Area | What Was Checked | Result |
|---|---|---|
| Auth on sensitive routes | /api/wallet/keys, /api/wallet/os-store, /api/agent/reset |
✅ All gated behind ensureCompatSensitiveRouteAuthorized() |
| Token comparison | Timing-safe comparison | ✅ Uses crypto.timingSafeEqual() |
| Security headers | X-Content-Type-Options, X-Frame-Options, X-XSS-Protection | ✅ All set correctly |
| DNS rebinding | Auth checked before CORS | ✅ Implemented at packages/agent/src/api/server.ts:5821-5824 |
| Deep link validation | validateAndSetApiBase() |
✅ Blocks public IPs over HTTP, validates localhost/loopback |
| Null origin | file:// origin handling |
✅ Requires explicit ELIZA_ALLOW_NULL_ORIGIN=1 flag |
| Plugin migrations | SQL migration system | ✅ Both @elizaos/plugin-sql and @elizaos/plugin-todo migrated successfully |
Prioritized Fix Checklist
P0 — Critical
- UX-1: Fix entity initialization hang — investigate why "INITIALIZING ENTITY" never resolves in dev mode. Check if the database "shutting down" error causes entity creation to fail silently.
P1 — High
- SEC-1: Add auth middleware to
/api/configroute atpackages/app-core/src/api/server.ts:3193— this endpoint returns the cloud API key unauthenticated - SEC-2: Add auth middleware to
/api/database/tablesroute — full schema exposure is an information disclosure risk
P2 — Medium
- SEC-3: Add auth to
/api/permissionsendpoint — platform info leakage - UX-2: Add loading timeout (30s) with retry button and error message to the loading/initializing component
- UX-3: Handle database "shutting down" error gracefully in
@elizaos/plugin-sql— add retry logic or surface error to UI - A11Y-1: Add
role="tablist"andaria-selectedto mode toggle buttons
P3 — Low
- A11Y-2: Add
aria-live="polite"to loading status region - UX-4: Disable chat input (
textbox "Chat message") while entity is initializing - Add
aria-label="Attach file"to the unlabeled file upload button
Positive Security Findings (Do-Not-Regress)
- Timing-safe token comparison —
crypto.timingSafeEqual()inpackages/app-core/src/api/auth.ts:36-41 - Auth before CORS — DNS rebinding prevention at
packages/agent/src/api/server.ts:5821-5824 - Security headers — nosniff, DENY, XSS protection at
packages/agent/src/api/server.ts:6358-6361 - Sensitive route protection — wallet, agent reset, plugin mutation endpoints all gated
- Deep link URL validation —
validateAndSetApiBase()inapps/app/src/main.tsx:243-280blocks unsafe origins - Null origin protection — requires explicit
ELIZA_ALLOW_NULL_ORIGIN=1forfile://origins - Wallet key temporal gating —
/api/wallet/keysdisabled after onboarding atpackages/app-core/src/api/server.ts:2428-2432 - Referrer policy —
strict-origin-when-cross-originatpackages/agent/src/api/server.ts:5954
Reactions are currently unavailable