Project Nūr is currently a research prototype. Only the main branch is
supported. There are no backported security fixes.
Please do not file public GitHub issues for security or privacy vulnerabilities. Instead, email the maintainer directly:
- Contact: balfiky@yahoo.com
- Subject prefix:
[nur-security]
Please include:
- A description of the issue and the impact
- Steps to reproduce, ideally with a minimal script or config
- Your suggested fix if you have one
You should receive an acknowledgement within a few business days. We'll work with you on a disclosure timeline. Public disclosure should wait until a fix is available or we've agreed on a timeline.
These areas process or persist potentially sensitive user content and warrant extra scrutiny:
runtime/sessions/persistence.py— writes per-session engine state todata/<platform>_<user_id>/sessions/<chat_id>.jsonand active hot transcripts todata/<platform>_<user_id>/sessions/<chat_id>.history.json.data/is gitignored; never commit it.core/memory/long_term.py,core/memory/relationship.py,core/memory/semantic.py— SQLite tables indata/<platform>_<user_id>/nur.dbstoring distilled user memory (memories), relationship events (relationship_events), open loops (open_loops), and semantic preferences (semantic_memories). The shared self-model lives indata/shared/self_model.db. See PRIVACY.md for full layout.runtime/life_history.py— shared identity-level experience and evolution storage indata/shared/life_history.db. Pasted text and local-file excerpts can be persisted as evidence for belief/drive changes.runtime_config.yaml— may contain API keys. The secret fields (enumerated inruntime/config.py:_SECRET_FIELDS) aretelegram_token,llm_api_key, andapi_key. Keep real values out of committed files; useruntime_config.example.yamlas the tracked starter and inject real values locally or via environment variables.interface/api.pyandinterface/v1.py— CORS and bearer-auth handling. The defaultcors_origins: []is same-origin only; avoid widening it without careful thought.llm_backend: codex— delegates response generation to the local Codex CLI. Nūr invokes it withcodex exec --sandbox read-only --ephemeral; keepNUR_CODEX_WORKDIRunset unless the backend should have read-only context from a specific local directory.runtime/channels/telegram.py— allowlist logic controls who can chat. Misconfiguration exposes the system to arbitrary Telegram users./admin— operator console for configuration, diagnostics, redacted export, backup, guarded session reset, guarded user deletion, skill management, and Life History intake/observability. Setapi_keybefore exposing the server beyond localhost.
Nūr ships with a builtin agentic tool layer (tools/builtin/) that can
match user text to actions like fs.read_file, fs.write_file,
fs.delete_path, shell.run_command, and web/browser/calendar calls via
regex heuristics in core/dual_process/tool_loop.py. External tools are
off by default (tools_enabled: false). With tools_enabled: false,
runtime/tools.py still wires Nūr's internal skill-registry tools
(skills.create, skills.audit, skills.enable, etc.) into the executor
so the assistant can manage durable skills through the observable tool
trace; filesystem, browser, web, calendar, and shell capabilities remain
excluded until tools_enabled: true, and shell.run_command additionally
requires shell_tool_enabled: true.
Additionally, the native tool-controller system prompt
(nur_tools/native_orchestrator.py) only emits the "diagnose, install,
retry" directive — which lets the model unilaterally run package-manager
commands on missing-dependency errors — when
autonomy_level: high_risk. Under assisted (default) and autonomous
the prompt explicitly instructs the model to report dependency failures
honestly rather than silently install packages.
When you turn external tools on:
- Filesystem tools are sandboxed to
tools_workspace— paths that resolve outside that directory are refused. The default workspace is<data_dir>/workspace. - Life History local-file intake also reads only from
tools_workspace; operators should treat that workspace as readable by the assistant runtime. shell.run_commandis a separate opt-in viashell_tool_enabled: truebecause subprocess execution has a larger blast radius than bounded file I/O.- The HTTP surface (
/chat,/v1/chat) routes user messages through the same regex intent parser, so authenticating the endpoint is not a substitute for sandboxing — an authenticated attacker (or the user's own mis-addressed command) can still reach the tool layer. Setapi_keyand keepshell_tool_enabled: falseunless you trust every caller.
Bearer auth on nur-web is opt-in, matching the convention of
other local-LLM tools (Ollama, LM Studio, Jupyter). With no api_key
set in runtime_config.yaml, the HTTP surface is open. On a non-loopback
bind (--host 0.0.0.0 or any non-127.0.0.1/localhost/::1 value)
the launcher prints a one-screen warning to stderr so the operator
knows the surface is reachable from the network.
Set api_key: <a-strong-token> in runtime_config.yaml and restart to
require bearer auth on /chat, /debug, /config, /session/end,
/rest, /ws, every /admin/* JSON endpoint, and every /v1/*
endpoint except /v1/health and /v1/ready. This is recommended any
time more than one person can reach the host (multi-user tailnet,
shared LAN, public IP).
On first run the launcher also auto-creates runtime_config.yaml with
safe defaults (mock LLM backend, tools off, shell off, no Telegram) if
the file does not already exist, so a clean pip install → nur-web
flow works without a separate nur-setup step. The browser setup
wizard at / walks the operator through model, identity, and tool
settings.
When api_key is set, every mutating and data-bearing endpoint on the
standalone web server requires Authorization: Bearer <api_key>:
/chat, /debug, /config (GET and POST), /session/end, /rest,
/ws, every /admin/* JSON endpoint (status, config, test, diagnostics,
export, backup, sessions/reset, users/delete), and every /v1/*
endpoint except /v1/health and /v1/ready. Static assets (GET /,
GET /admin HTML shell) remain open so the bundled UI can bootstrap and
prompt for the bearer token client-side.
Nūr persists emotional and relational state about its users. Do not deploy it against people who have not consented to that persistence. See PRIVACY.md for retention and deletion guidance and docs/DEPLOYMENT_AND_ADMIN.md for deployment hardening.