This policy covers the ContextGO monorepo runtime. The primary entry points are:
src/contextgo/context_cli.py- unified CLIsrc/contextgo/context_daemon.py- background sync daemonsrc/contextgo/context_maintenance.py- maintenance utilitysrc/contextgo/session_index.py- session indexingsrc/contextgo/memory_index.py- memory/observation indexingsrc/contextgo/memory_viewer.py- local HTTP viewer server- Native backends:
native/session_scan(Rust),native/session_scan_go(Go)
Out-of-scope: third-party dependencies, downstream forks, or deployment infrastructure not included in this repository.
Only the latest commit on the main branch is actively supported with security fixes. We do not backport fixes to older releases.
Do not open a public GitHub issue for security vulnerabilities.
To report a vulnerability privately:
- Report via GitHub Security Advisories at https://github.com/dunova/ContextGO/security/advisories/new
- If you prefer, contact the maintainers directly via the repository's Security tab (Report a vulnerability button).
- Encrypt sensitive reports using the maintainer's public PGP key if one is published in the repository.
Please provide:
- A clear description of the vulnerability and affected component(s)
- The version or commit hash where you observed the issue
- Step-by-step reproduction instructions (proof-of-concept code or commands)
- The potential impact and attack scenario
- Any suggested mitigations or patches
- Acknowledgement: within 72 hours of receipt
- Initial triage: within 7 days
- Fix or mitigation: within 30 days for critical/high severity; 90 days for medium/low
- Public disclosure: coordinated with the reporter after a fix is available
We follow responsible disclosure: if a fix is delayed beyond the agreed timeline, the reporter may publish after giving 7 days notice.
By default ContextGO operates entirely on the local filesystem. No network requests are made unless explicitly configured:
CONTEXTGO_ENABLE_REMOTE_SYNC=0(daemon remote sync, default: off)CONTEXTGO_ENABLE_REMOTE_MEMORY_HTTP=0(CLI HTTP export, default: off)- The memory viewer binds to
127.0.0.1by default and requires a token when bound to any non-loopback address.
The daemon refuses to start if CONTEXTGO_REMOTE_URL is set to a non-localhost HTTP URL. Only https:// is accepted for remote hosts. This is enforced at module import time in context_daemon.py.
context_config.storage_root() validates that the resolved path is absolute and has at least three path components (e.g. /home/user/.contextgo) to prevent accidentally using /, /tmp, or similarly dangerous roots.
- Storage root, pending directory, log directory:
0700 - Memory markdown files, SQLite index databases, lock files, health cache:
0600 - These permissions are set at creation time using
os.open(..., 0o600)/os.chmod(...).
The daemon checks that the configured storage root is not a symlink to a directory owned by another user. Source history files (shell history, JSONL files) that are symlinks are silently skipped via SessionTracker._is_safe_source().
All content written to the index passes through strip_private_blocks() (removes <private>...</private> blocks) and the daemon's SECRET_REPLACEMENTS list, which redacts common credential patterns (API keys, tokens, passwords, PEM blocks, OAuth tokens, AWS access key IDs).
The memory viewer uses hmac.compare_digest for X-Context-Token header comparison to prevent timing-based token enumeration attacks.
The memory viewer parses the Origin request header with urllib.parse.urlparse and checks only the hostname component against the loopback allowlist (127.0.0.1, localhost, ::1). This prevents substring-bypass attacks such as http://evil127.0.0.1.attacker.com that would pass a naive in-based string check.
All SQLite queries use parameterized placeholders (?) for user-supplied values. WHERE clauses are constructed from hardcoded predicate strings; user input flows only through bind parameters. Dynamic IN (...) placeholders are built from ",".join("?" for _ in items) so the number of ? tokens always matches the bind arguments without interpolating any user data into the SQL string.
All subprocess.run / subprocess.Popen calls pass arguments as lists (never shell=True). Command arguments derived from user input (query strings, paths) are passed as separate list elements, never interpolated into shell strings.
Rust and Go build artifacts default to ~/.cache/contextgo/target (a user-owned directory) rather than a shared /tmp path to prevent TOCTOU races from other users on multi-tenant systems. Override with CONTEXTGO_NATIVE_TARGET_DIR.
The HTML viewer page is served with a restrictive Content-Security-Policy header (default-src 'self'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; connect-src 'self'; img-src 'none'; object-src 'none'; base-uri 'none'; form-action 'self'). All JSON API endpoints receive X-Content-Type-Options: nosniff, X-Frame-Options: DENY, and Referrer-Policy: no-referrer.
-
No secrets in commits: API keys, tokens, passwords, or machine-specific absolute paths must never appear in committed files. Replace with
XXXand document in the PR description. -
No pickle / eval / exec: Deserializing untrusted data with
pickle, or executing dynamic code viaeval/exec, is prohibited. All external data is parsed as JSON. -
Dependency review: New third-party dependencies require explicit justification. Prefer stdlib where feasible.
-
Environment variable documentation: Any new
CONTEXTGO_*environment variable must be added to.env.examplewith a description before merging. -
Verification commands (run before each PR and after security-relevant changes):
contextgo health contextgo smoke python3 scripts/smoke_installed_runtime.py python3 -m benchmarks --iterations 1 --warmup 0 --query benchmark bash -n scripts/*.sh python3 -m pytest tests/test_context_core.py
- The local memory viewer (
contextgo serve) is intended for single-user localhost use only. It is not hardened against adversarial clients on the network. Do not expose it to untrusted networks even with a token. - Shell history indexing reads
~/.zsh_historyand~/.bash_history. These files may contain sensitive commands. The daemon applies secret-pattern redaction before indexing, but this is best-effort and not a substitute for managing shell history hygiene. - The tool does not encrypt data at rest. Filesystem-level encryption (e.g. FileVault, LUKS) is recommended for sensitive environments.