Security
Nebo runs an AI agent with access to your file system, shell, and network. Here's exactly how we prevent that from going wrong.
The design principle is defense in depth. Seven independent security layers, each assuming the one above it might fail. No single bypass, no matter how clever, can compromise your system because every layer enforces its own rules independently.
We also believe in radical transparency. This page doesn't just list what we protect against. It documents every vulnerability we've found, how we fixed it, and what's still open. If we haven't fixed it yet, you'll know.
The Seven Layers
Hard Safeguard
Unconditional. Cannot be overridden by any setting, mode, or user.
Origin-Based Restrictions
Different sources get different permissions
Tool Policy & Approval
User-configurable guardrails with sensible defaults
Capability Permissions
Turn entire categories on or off
App Sandbox
Third-party code runs in a sealed environment
Compiled-Only Binary Policy
The anti-self-modification layer
Network Security
Authentication, CSRF, headers, rate limiting
Hard Safeguard
Unconditional. Cannot be overridden by any setting, mode, or user.
The innermost safety rail. Runs inside the tool registry before every single tool call. No autonomous mode, no policy level, no user approval can bypass it.
Privilege Escalation Blocked
sudo blocked in all forms: direct, piped, chained, subshell. su blocked entirely. Nebo must never run commands with elevated privileges.
Disk Destruction Blocked
mkfs, fdisk, gdisk, wipefs, diskutil erase, dd to block devices. All blocked unconditionally. Cannot format, partition, or wipe drives.
Filesystem Destruction Blocked
rm -rf / (all variants), writing to /dev/ (except null/stdout/stderr), fork bombs. Detected and blocked.
System Paths Protected
/System, /bin, /sbin, /usr/bin, /etc, /Library/LaunchDaemons are all write-protected. Reads allowed, writes blocked. Same for Linux and Windows equivalents.
Self-Harm Prevention
Nebo cannot modify or delete its own database, WAL files, or data directory. Prevents the agent from destroying its own persistence.
Credential Paths Protected
~/.ssh/, ~/.gnupg/, ~/.aws/credentials, ~/.kube/config, ~/.docker/config.json are blocked from writes. Your keys stay untouched.
Origin-Based Restrictions
Different sources get different permissions
Every request is tagged with where it came from. Non-user origins have hard restrictions. No approval prompt, no override possible.
User Origin
Direct interaction via web UI or CLI. Full access, governed by your policy settings.
Comm Origin
Inter-agent communication (NeboLoop). Shell access denied. A remote agent cannot execute commands on your machine.
App Origin
Third-party app output. Shell access denied. App outputs re-entering the conversation cannot escalate to shell execution.
Skill Origin
Matched skill templates. Shell access denied. Prevents skill supply chain attacks from reaching your shell.
Tool Policy & Approval
User-configurable guardrails with sensible defaults
Three policy levels control what auto-approves and what prompts you. The default is allowlist mode: only known-safe commands run without asking.
Allowlist Mode (Default)
Read-only commands (ls, cat, grep, git status, etc.) auto-approve. Everything else prompts you for approval before executing.
Deny Mode
Every single operation requires explicit approval. Maximum control.
Dangerous Command Detection
rm -rf, chmod 777, curl | sh, eval, exec are flagged automatically regardless of policy level.
Autonomous Mode
Opt-in only. Requires accepting terms, typing "ENABLE" to confirm, and acknowledging liability. When disabled, all permissions reset to safe defaults.
Capability Permissions
Turn entire categories on or off
Broad permission categories that control what tools the AI can even see. Disabled categories aren't just blocked. The LLM never knows they exist.
8 Permission Categories
File System, Shell & Terminal, Web Browsing, Contacts & Calendar, Desktop Control, Media & Capture, System, Chat & Memory (always on).
Invisible When Disabled
If you disable Shell & Terminal, the AI has no concept of shell commands. It's not blocked. It literally doesn't know shell exists as an option.
App Sandbox
Third-party code runs in a sealed environment
Apps (.napp packages) from NeboLoop run in a sandbox with strict isolation. Deny-by-default permissions, environment sanitization, and cryptographic signing.
Environment Isolation
Only 7 environment variables passed to apps (PATH, HOME, TMPDIR, LANG, LC_ALL, TZ, NEBO_APP_*). All API keys, tokens, and secrets stripped.
ED25519 Signing
Every app binary is cryptographically signed. Manifest signature verifies integrity. Binary signature verifies the code. Any modification, even one byte, breaks the signature.
Deny-by-Default Permissions
Apps must declare every permission they need: network, filesystem, shell, memory, channels. Unknown permissions rejected. Permission changes on updates require re-approval.
Seven-Layer .napp Extraction
Symlink rejection, hard link rejection, path traversal detection, path escape checks, filename allowlists, size limits, required file validation. All checked during extraction.
Revocation & Quarantine
Background goroutine checks all running apps against revocation list every hour. Revoked apps: process killed, binaries removed, data preserved, quarantine marker written.
Compiled-Only Binary Policy
The anti-self-modification layer
This is unique to AI agent platforms. Nebo runs third-party code on your machine, and the agent has file system access. If an app's source code were readable, the agent could modify it. Compiled binaries make app code opaque and immutable.
The Threat
An interpreted app (Node.js, Python) has its source code sitting on disk as plaintext. The AI agent, or an attacker who compromises it via prompt injection, could rewrite the app's logic, inject backdoors, or escalate privileges. The modified code persists across restarts.
The Solution
Only compiled native binaries (Go, Rust, C, Zig) are allowed. The agent cannot meaningfully read or modify machine code. Random byte changes crash the binary instead of changing behavior. ED25519 signatures detect any tampering.
Two-Tier Validation
NeboLoop performs deep analysis once per upload (magic bytes, hidden interpreter detection, dynamic link analysis, dropper pattern detection). Nebo performs fast checks on every launch (magic bytes + signature verification).
Interpreter Wrappers Rejected
PyInstaller, Node.js SEA, JVM wrappers are all detected and rejected. They're compiled wrappers around interpreted runtimes, not true native binaries. NeboLoop scans for _PYINSTALLER strings, libpython/libnode/libjvm dynamic links, and _MEI temp directory markers.
Network Security
Authentication, CSRF, headers, rate limiting
Standard web security, done thoroughly. JWT auth, CSRF protection, security headers, CORS, rate limiting, input sanitization, and SSRF protection.
Authentication
JWT (HMAC-SHA256) for all API requests. WebSocket connections require authentication. Passwords: bcrypt cost 12, minimum 8 chars with complexity requirements.
CSRF Protection
Random 32-byte tokens with HMAC-SHA256 signing. Constant-time comparison (no timing attacks). 12-hour expiry. SameSite: Strict cookies.
Security Headers
CSP: default-src 'self', object-src 'none', frame-ancestors 'none'. X-Frame-Options: DENY. HSTS: 1-year with preload. Permissions-Policy blocks camera, microphone, geolocation, payment.
SSRF Protection
Three-layer defense: pre-flight URL validation (blocks private IPs, cloud metadata), connection-time re-validation (catches DNS rebinding), redirect validation (every hop checked). 25 test cases.
Rate Limiting
Token bucket per-client. General: 100 req/min. Auth: 5 req/min. Trusted proxy support that only trusts X-Forwarded-For from known proxy IPs.
Input Sanitization
40+ SQL injection patterns, XSS detection, identifier validation, HTML entity escaping, null byte stripping, UTF-8 validation. All queries use parameterized statements (sqlc-generated).
Vulnerability Log
Every vulnerability we've found, how we fixed it, and what's still open. No hiding.
Resolved 8 fixed
Cross-Site WebSocket Hijacking
Both WebSocket endpoints had CheckOrigin: return true, allowing any webpage to control the agent remotely.
Fix: Added IsLocalOrigin() validation. Only localhost/127.0.0.1 accepted. Applied to all WebSocket upgrade endpoints.
Shell Injection: No Env Sanitization
bash -c ran with full parent environment. PATH, LD_PRELOAD, DYLD_INSERT_LIBRARIES all inherited.
Fix: Added sanitizedEnv() stripping 30+ dangerous variables. Absolute /bin/bash path prevents binary substitution. Applied to foreground and background execution.
SSRF in Web Fetch
web_tool.go accepted any URL with no validation. No private IP checks, no scheme validation, followed redirects to internal IPs.
Fix: Three-layer SSRF protection: pre-flight validation, connection-time re-validation (catches DNS rebinding), redirect validation. 25 test cases.
DNS Hijack via local.nebo.bot
All references to local.nebo.bot posed a DNS hijack risk. Domain compromise would bypass CORS/origin checks.
Fix: Replaced all 15 references with localhost. Default BaseURL changed to http://localhost:27895.
No Origin Tagging
No way to distinguish user commands from remote MQTT messages or app output.
Fix: Implemented 5 origin types (user, comm, app, skill, system) with context propagation through the entire execution chain.
No Origin-Aware Policy
Tool registry only checked policy level, not who was requesting. Remote agents could access any tool.
Fix: Origin-based deny lists with secure defaults. comm/app/skill origins denied shell access unconditionally.
Path Traversal in File Tools
file_tool.go had no path restrictions. Agent could read ~/.ssh/id_rsa, write to ~/.bashrc.
Fix: Added validateFilePath() with ~25 sensitive path blocks, symlink resolution via filepath.EvalSymlinks. Applied to read, write, and edit. 12 tests.
Dev-Login Bypass
/api/v1/auth/dev-login returned valid JWT for hardcoded emails without password verification.
Fix: Deleted entirely. Handler, route, frontend page, and API client function all removed.
Open 5 in progress
Credential Storage
LLM provider API keys stored in plaintext in auth_profiles table. MCP tokens encrypted but key file sits alongside database.
Plan: OS Keychain integration (macOS Keychain, Windows DPAPI, Linux libsecret) to tie credential access to user login session.
CDP Endpoint Authentication
Chrome extension relay CDP endpoint allows unauthenticated loopback connections. Any local process can take browser control.
Plan: Auth token requirement for all connections, connection rate limiting, CDP command logging.
Web Content Sanitization
Raw HTML returned to LLM with only length truncation. Malicious webpages can inject instructions into agent context.
Plan: HTML tag stripping, script/style removal, special character escaping before LLM processing.
Memory Prompt Injection
Stored memories concatenated directly into system prompt with zero escaping. Time-shifted prompt injection possible.
Plan: Sanitization of stored values, structured delimiters (XML/JSON tags), content-type validation.
Compaction Summary Poisoning
Poisoned conversations get compressed into summaries that persist across sessions via prompt injection.
Plan: Structured state snapshots instead of prose, summary sanitizer, provenance tracking.
Design Principles
Defense in Depth
Multiple independent layers, each assuming others might fail. No single point of failure.
Fail Closed
When in doubt, block the operation. Err on the side of safety.
Least Privilege
Deny by default, require explicit opt-in for every capability.
No Silent Failures
Blocked operations explain why and tell you what to do instead.
Unconditional Safety
Critical protections like system paths, sudo, and disk formatting cannot be overridden by any setting, mode, or configuration. These are hard limits, not suggestions.
Report a Vulnerability
If you discover a security issue, email security@neboloop.com and please follow these guidelines:
- 1. Do not open a public GitHub issue. Public disclosure before a fix is available gives attackers a head start on every user running Nebo.
- 2. Email security concerns to the maintainers directly. Private reporting lets us triage and fix the issue before it becomes a target.
- 3. Include steps to reproduce the vulnerability. Reproducible reports let us confirm and fix the issue faster. Vague reports can sit in triage for weeks.
- 4. Allow reasonable time for a fix before public disclosure. We commit to acknowledging reports within 48 hours and shipping fixes as fast as possible. Coordinated disclosure protects everyone.
Related Content
Why Personal Desktop AI Companions Must Never Run Interpreted Code
An AI agent with file system access and an interpreted runtime is a self-modifying program waiting to happen. Here is the threat model and the compiled-only binary policy I built to prevent it.
Introducing GoBot, an Autonomous AI Agent That Actually Controls Your Desktop
GoBot is a persistent AI agent that remembers conversations, controls your desktop, runs scheduled tasks, and works across multiple channels. Tonight I watched it check my Gmail, compose an email, and click Send. All by itself.
I Reduced My MCP Tools from 96 to 10. Here's the Pattern.
MCP tool bloat is choking LLMs. The Single Tool Resource Action Pattern (STRAP) applies REST-style routing to consolidate 96 operations into 10 tools with the same functionality.