newOS4 Code Review
Reviewed by GLM 5.2 (z-ai/glm-5.2) · v4.5.83 · 2026-07-03 · ~48K LOC across 54 modules
1. Architecture
Strengths
- Consistent module pattern — All 43 modules follow the same interface:
commands{}, registerCommands(), getHelpInfo(), init(terminal)
- _safeRegister pattern (terminal.js:1216) — Uses typeof registry map instead of eval for safe class lookup
- /sys/ virtual filesystem (virtual-fs.js:33-217) — Lazy-initialized virtual mounts with factory functions, never persisted, computed on demand
- VFS persistence — Debounced (2s), compressed, IndexedDB fallback when localStorage quota exceeded
- Security manager — Clean 4-level model with Levenshtein suggestion engine using Uint16Array
Weaknesses
MEDIUM
terminal.js:13 + module-aiassist.js:1646-1661
Two divergent security whitelists — WebX11SecurityManager whitelist (~80 commands) and AI isDestructive safeRead set (~60 commands) are maintained separately. Synced in v4.5.74 but will drift as new commands are added.
MEDIUM
module-manager.js:70, core-bundle.js:1052
new Function module loading —
new Function('return ' + cleanCode + '\nreturn ' + className)() executes module source with full page origin access. SRI on wpm mitigates install vector but editor-saved modules and persisted reloads have no integrity check.
LOW
module-loader.js
Procedural loader, not a class — Cannot be inspected via module-info. By design (runs before classes available) but creates inconsistency.
LOW
terminal.js:1339
Hardcoded skipList — 21 module names hardcoded in reloadPersistedModules. New ext modules require manual list update or they double-load.
2. Security
Strengths
- 4-tier security model — Permissive(0)/Standard(1)/Paranoid(2)/Audit(3) with command classification into destructive/system/suspicious/unknown
- Pipe bypass fixed (v4.5.63) — executePipeChain now calls security._classify() on each stage
- Guardrail layer — 8 rules loaded (rm-rf-block, curl-pipe-bash, eval-danger), runs before every AI tool execution
- SecretVault — AES-GCM + PBKDF2 at 600K iterations (OWASP 2023), sync name-only redaction (no decryption side-channel)
- Confidence escalation — AI can auto-approve destructive tools at ≥90% confidence (configurable)
Vulnerabilities
CRITICAL
module-aiassist.js:1655 + console.js:31-37
AI can execute arbitrary JavaScript without confirmation
node is in the AI's safeRead whitelist. The node -e "..." command (console.js:31) uses raw eval() in full page context. AI can read/write localStorage (including encrypted secrets if vault unlocked), make fetch requests, modify DOM, exfiltrate data — all without user confirmation.
Fix: Remove node from the safeRead set in isDestructive(). All JS execution commands should require confirmation.
CRITICAL
module-aiassist.js:1633
shadowRollback() persistence is broken
Calls this.terminal.fs.saveToLocalStorage() which doesn't exist (actual method is saveToStorage()). VFS rollback restores in-memory state but never persists. On page reload, pre-rollback (damaged) state reappears. Silent data loss.
Fix: Change saveToLocalStorage() → saveToStorage() at module-aiassist.js:1633 and core-bundle.js:9278.
HIGH
terminal.js:1413-1424
capturePipeOutput lacks try/finally — print method leak on error
If dispatchCommand throws, this.print is never restored. All subsequent terminal output goes to a local variable. Terminal appears dead.
Wrap in try/finally to restore this.print.
HIGH
module-orchestrator.js:173-178
Orchestrator timers bypass central registry
3 raw setInterval calls (500ms A2A polling, 3s heartbeat, 30s idle sweep) not registered in _timers[]. clearAllTimers() doesn't clear them. On module unload, zombie timers continue polling VFS.
Use this.terminal.moduleManager._setInterval() instead of raw setInterval().
HIGH
module-aiassist.js:1062-1066
Confidence escalation can be gamed by prompt injection
AI's own preamble text determines whether destructive tools auto-approve. If model outputs "Confidence: 95%" (genuine or injected), it bypasses human confirmation. Self-reported, not system-computed.
MEDIUM
terminal.js:1371-1382
splitPipe doesn't distinguish quote types
echo 'a|b' | cat splits at the | inside single quotes because both quote types toggle the same inQuote boolean.
Track inSingle and inDouble separately (like _parseArgs does).
MEDIUM
module-aiassist.js:1379
Guardrail rules stored in localStorage, user-editable
Any code with localStorage access (including js/node commands) can modify or delete guardrail rules. Guardrail layer is bypassable by anyone who can execute JS in page context.
MEDIUM
module-aiassist.js:1670
Guardrail check uses command-oriented regex on structured args
Guardrail regex patterns designed for command-string format (/rm\s+-rf/) but tool calls use structured JSON args. Pattern mismatch means some destructive tool calls may bypass guardrail rules.
3. Code Quality
HIGH
core-bundle.js (16K+ lines)
Massive code duplication between source and bundle
Every fix must be applied to both the source file AND the bundle. The saveToLocalStorage bug exists at core-bundle.js:9278 too. Rebuild script mitigates but only if run after every change.
MEDIUM
module-aiassist.js:914-1114
agenticLoop is a 200-line monolith
Entire tool-calling loop (loop detection, parallel safe-tool execution, destructive tool confirmation, confidence parsing, tool result logging, memory graph recording, debug panel updates) is one method. Functional but unmaintainable.
MEDIUM
All modules
71% of localStorage writes uncovered by try/catch
162 localStorage.setItem calls, only 47 wrapped in try/catch. If localStorage fills up (5-10MB limit), remaining 115 calls throw unhandled QuotaExceededError.
MEDIUM
All modules
44% of fetch calls have no timeout
105 fetch() calls, only 61 with AbortController/signal. A hung Ollama or SearXNG backend freezes the UI indefinitely.
LOW
terminal.js:81-97
_parseArgs doesn't handle escaped quotes
\" inside a double-quoted string is treated as closing quote. No backslash escaping support.
LOW
terminal.js:22
Duplicate 'cat' in internals list
'cat' appears twice in _registerBuiltIn array. Harmless but sloppy.
4. Performance
MEDIUM
virtual-fs.js:425
VFS saveToStorage serializes entire filesystem
JSON.stringify({ root, currentPath }) creates multi-MB string every 2 seconds (debounced). Synchronous, blocks main thread. IndexedDB fallback helps on overflow but serialization itself is the bottleneck.
MEDIUM
module-orchestrator.js:173
A2A polling at 500ms
Polls VFS mailboxes every 500ms regardless of agent activity. With 5 agents, that's 10 VFS reads/second. Event bus provides instant in-memory delivery, making VFS poll redundant for same-page agents.
MEDIUM
virtual-fs.js:55-74
vfsWalk is unbounded synchronous recursion
No depth limit. On deep directory structures, can stack overflow. /sys/vfs/stats and /sys/vfs/largest call this on every cat.
LOW
terminal.js:42-53
_collectAllCommands iterates all modules on every suggestion
Every unknown command triggers Levenshtein comparison against ~430 commands. Acceptable now but won't scale.
5. AI Integration
Strengths
- Well-structured agent loop — Loop detection (6x same tool+args in 30s → break), parallel safe-tool execution, sequential destructive confirmation, confidence escalation, last-turn prompt injection, memory-augmented planning
- 35+ tools — VFS operations, web search/fetch, module management, skills CRUD, VaultMind, wallet lookup, usage stats. Filtered by active loop profile.
- 6 agent loop profiles — default, coder, creative, research, safe, minimal with per-profile tool restrictions and temperature
Issues
MEDIUM
module-aiassist.js:44-53
AI conversation context stored in plaintext localStorage
Up to 10 context messages persisted to webx11_ai_context. Sensitive AI discussions persist across sessions in plaintext. No encryption, no expiry.
LOW
module-aiassist.js:1042
_summarizeObservation truncates to 150 chars
Tool results summarized for display but full result pushed to messages. Fine for display but LLM sees full results while user sees truncated ones.
6. Top 5 Recommendations
#1
module-aiassist.js:1655
Remove node/js/js-run from AI safeRead whitelist
Immediate security hole — AI can execute arbitrary page-context JS without confirmation. One-line fix.
#2
module-aiassist.js:1633
Fix shadowRollback() persistence
Guardrail rollback — key safety mechanism — is silently broken. saveToLocalStorage() → saveToStorage().
#3
terminal.js:1413-1424
Wrap capturePipeOutput in try/finally
Single thrown error in any pipe stage permanently breaks terminal output. Trivial fix with high impact.
#4
module-orchestrator.js:173-178
Migrate orchestrator timers to central registry
3 zombie timers survive module unload. Use _setInterval() instead of raw setInterval().
#5
terminal.js:13 + module-aiassist.js:1646-1661
Consolidate the two security whitelists
Single SecurityManager.getSafeReadCommands() method eliminates drift between terminal whitelist and AI safeRead set.
Review generated by GLM 5.2 (z-ai/glm-5.2) via Hermes Agent · newOS4 v4.5.83 · 2026-07-03