Skip to content

Security: frpboy/lean-ctx

Security

SECURITY.md

Security Policy

Reporting a Vulnerability

If you discover a security vulnerability in lean-ctx, please report it privately:

Please do NOT:

  • Open public GitHub issues for security vulnerabilities
  • Disclose vulnerabilities on social media or forums before we've had a chance to address them

What lean-ctx Does (and Doesn't Do)

LeanCTX is the Context Gateway for AI Systems. Control what your AI can see. This policy covers the open-source LeanCTX Engine and its local CLI, MCP, HTTP, hook, and supported proxy paths. LeanCTX SDK and commercial Enterprise deployments have separate integration and operating contracts.

The Engine runs locally, but enabled providers, upstream model traffic, updates, telemetry, and other configured integrations can make network requests. Review the configured integration and deployment rather than infer data locality from the word “local.”

Context selection determines what AI should see; permissions and configured content controls constrain what it may see. Receipts describe observed context operations, not prompts or delivery outside the integration's visibility.

Does:

  • Read files from your local filesystem (explicit reads and tool-driven scans within the project boundary)
  • Execute shell commands (only commands you or your AI tool explicitly invoke)
  • Cache file contents in memory during a session
  • Store statistics in ~/.lean-ctx/stats.json (command counts, token savings)
  • Store session state in ~/.lean-ctx/sessions/ (task context, findings)

I/O Boundary (PathJail + Roles)

lean-ctx enforces a filesystem boundary for tool I/O:

  • PathJail: all tool path inputs are resolved (symlinks and .. included) and checked against the jail scope (path_jail_scope, global-only):
    • home (default since v3.11.1; read and write below ~ since v3.11.3): every path below the user's home directory, except the protected zones — every top-level dot entry (~/.ssh, ~/.aws, ~/.gnupg, ~/.config, shell rc files, other agents' ~/.claude / ~/.codex / ~/.cursor), ~/Library, ~/AppData / NTUSER.DAT* and ~/snap. Everything outside ~ stays jailed. Zones are a hard deny: a root or allow entry that merely contains a zone does not open it. An implausible $HOME (/, /root, /tmp, not owned by the user) disables the scope.
    • projects (the default of v3.11.1–v3.11.2): only paths inside a project below ~ (a folder between it and ~ holds .git, Cargo.toml, package.json or another project marker) are readable; loose personal files stay jailed, and writes stay limited to the session's project, host-declared roots and explicit allow entries.
    • project: only the current project_root plus the explicit allow roots below.
    • If a path would escape, the call fails naming the single command that admits it (lean-ctx allow-path <dir>) and asks the agent to defer to the user.
  • Per-session project binding: the project root comes from the host session (MCP roots, host project env, working directory). Global agent configs no longer carry a LEAN_CTX_PROJECT_ROOT pin; lean-ctx doctor reports and doctor --fix removes old ones.
  • Explicit allow roots (lean-ctx allow-path <dir> writes allow_paths):
    • Env: LEAN_CTX_ALLOW_PATH (or LCTX_ALLOW_PATH) — a path list (: on Unix, ; on Windows)
    • Config: allow_paths in ~/.lean-ctx/config.toml (whitelist only); extra_roots (whitelist + multi-root scanning)
    • ~, $VAR and ${VAR} are expanded in these entries (no shell runs for config files)
  • Disabling the jail (sandboxed environments where the OS is the boundary):
    • Config: path_jail = false in ~/.lean-ctx/config.toml
    • Compile-time: the no-jail cargo feature
    • The legacy LEAN_CTX_NO_JAIL=1 env var was removed in v3.7.4 and has no effect
    • Full reference: docs/reference/appendix-paths-and-config.md §5; lean-ctx doctor reports the effective jail state
  • Symlink escape protection: canonicalization ensures that symlinks pointing outside the jail are rejected.

In addition, roles can restrict unsafe I/O:

  • Secret-like deny-by-default:
    • Search skips secret-like files (e.g. .env, *.pem, id_rsa, .ssh/, .aws/) unless the active role explicitly allows them.
    • Artifact registry resolution rejects secret-like artifact paths unless allowed (artifacts are indexed/shareable by design).
    • Direct reads/edits can warn or error depending on boundary mode.
  • .gitignore bypass is policy-gated:
    • ctx_search ignore_gitignore=true requires explicit role permission (typically the admin role).
  • Boundary mode:
    • Roles can set io.boundary_mode = "warn" | "enforce".
    • Env override: LEAN_CTX_IO_BOUNDARY_MODE=warn|enforce.
  • Auditability:
    • Boundary denials/warnings emit local PolicyViolation events (no secret content is returned as part of the violation).

Threat Model (v2)

Primary risks:

  • Accidental secret exfiltration to LLMs via ctx_read, ctx_search, compressed ctx_shell, archives, or exported artifacts.
  • Boundary escapes via absolute paths, symlinks, linked projects, or artifact path tricks.
  • Amplification / token burn by scanning large files or returning unbounded outputs.
  • ReDoS via user-supplied regex patterns in ctx_search.
  • Cross-workspace data access in team server deployments (IDOR).

Core mitigations:

  • PathJail + explicit allow roots (LEAN_CTX_ALLOW_PATH / allow_paths).
  • Role-gated unsafe I/O (ignore_gitignore, secret-like allow).
  • Secret-path handling — search skips recognized secret-like paths; direct-read warnings or rejection depend on the configured I/O boundary, permissions, and role.
  • Shell CWD jail enforcement — explicit cwd parameters are jail-checked, cd targets validated.
  • Deterministic redaction on tool outputs (non-admin roles, and for persisted archives).
  • Hard caps on reads and outputs to limit DoS/token burn.
  • Regex guards — pattern length (1024 chars) and DFA size (1 MiB) limits on ctx_search.
  • MCP message size limit — 32 MiB cap on JSON-RPC message size.
  • Constant-time token comparison in all auth paths (dashboard, HTTP server, team server).
  • Team server tenant isolation — workspace enforced from authenticated token, not query parameters.
  • JSON-RPC batch rejection — batch requests rejected on team server to prevent scope bypass.
  • Event payload redaction — REST API responses redacted to Summary level by default.
  • Pipeline archive redaction — shell output archives redacted before storage.
  • UDS socket permissions — 0o600 enforced on Unix domain sockets after bind.
  • Error response sanitization — internal details logged server-side, generic codes returned to clients.
  • MCP gateway output redaction — downstream ctx_tools call output (success and error text) passes secret detection before it reaches the model.
  • Signed handoffs and packages — handoff bundle signatures cover the signer id and key; context packages and addons must be signed unless a local import passes --allow-unsigned (allow_unsigned=true over MCP); /v1/a2a/handoff rejects unsigned bundles and context packages. An embedded key proves integrity only: a signer is reported as trusted only when its key is pinned in <data_dir>/trusted-signers.toml ([[signers]] subject = "<agent id or @namespace>", public_key = "<hex>") or held by a local agent identity. Remote pack install / addon add pin the namespace publisher key on first install and refuse a different key afterwards.
  • Bounded audit trail — <data_dir>/audit/trail.jsonl rotates at 32 MiB into trail.NNNNNN.jsonl; the hash chain continues across segments and verify checks all of them. Archived segments are not deleted automatically, because removing one breaks chain verification.

Optional network activity (review effective configuration):

  • Update check: a lightweight daily GET to api.github.com/repos/yvgude/lean-ctx/releases/latest to notify you of new versions. Sends only the current version as User-Agent. Disable with update_check_disabled = true in ~/.lean-ctx/config.toml or LEAN_CTX_NO_UPDATE_CHECK=1.
  • Telemetry: product telemetry is on by default since v3.11.0 (v3.10.5 and earlier defaulted it off); an explicit earlier opt-out is kept. Inspect your installed build with lean-ctx telemetry status and lean-ctx telemetry show. Disable sending with lean-ctx telemetry off, DO_NOT_TRACK=1, or LEAN_CTX_TELEMETRY=off. Enabled telemetry sends installation and aggregate usage metadata. Do not infer zero network activity from telemetry being disabled.
  • Configured providers and integrations: source connectors, upstream model requests, submitted feedback, and remote endpoints have their own payloads and credentials. Review each enabled path.

Limits:

  • Configured detectors recognize supported patterns; they do not detect every secret or sensitive datum.
  • Warning, redaction, and blocking are different actions. Roles, bypasses, allow roots, and disabled controls change the effective boundary.
  • Inputs, caches, archives, and integration credentials require appropriate host protection and retention settings.
  • The normal Engine runs as your user; a container, VM, or operating-system policy can supply an additional boundary.

Automated Security Checks

Every push and pull request triggers our CI security pipeline:

  1. cargo audit — Scans dependencies for known CVEs
  2. cargo clippy — Enforces Rust safety lints (warnings = errors)
  3. Dangerous pattern scan — Detects potentially unsafe code patterns:
    • Shell injection vectors (Command::new("sh") with user input)
    • Network operations (reqwest::, std::net::, hyper::)
    • Unsafe code blocks (unsafe {)
    • Environment manipulation (.env("LD_PRELOAD"))
    • Hardcoded secrets or obfuscated strings
  4. cargo test — Full test suite must pass

Critical Files Requiring Enhanced Review

Changes to these files receive extra scrutiny:

File Risk Why
rust/src/shell/ Shell execution Wraps your shell, executes commands
rust/src/server/ MCP protocol Handles all tool calls from AI editors/agents
rust/src/hooks/ Editor integration Installs hooks/config into Claude Code, CodeBuddy, Cursor, etc.
rust/src/core/cache.rs File caching Reads and stores file contents
rust/Cargo.toml Supply chain Dependency manifest
.github/workflows/*.yml CI/CD Release pipeline integrity

Dependency Security

The manifests and lockfile define the dependency set for a given release. Review rust/Cargo.toml, rust/Cargo.lock, enabled features, and the security workflow when assessing supply-chain exposure. Dependency counts, download counts, and recent commits alone are not evidence that a dependency is safe.


VirusTotal False Positives

Rust binaries are frequently flagged by ML-based antivirus engines (particularly Microsoft Defender's Wacatac.B!ml classifier). This is a known issue affecting many Rust projects:

  • Rust lang discussion on false positives
  • A low number of detections alone does not establish a false positive.
  • The !ml suffix in Wacatac.B!ml means "Machine Learning detection" (heuristic, not signature-based)

Why it happens:

  • Statically linked binaries (~30 MB) are unusual for Windows
  • strip = true + lto = true optimizations alter binary structure
  • New/unsigned executables trigger ML classifiers trained on known-good signed software

How to verify lean-ctx yourself:

  1. Build from source: cargo install lean-ctx (compiles on your machine)
  2. Compare SHA256 checksums against our GitHub Releases
  3. Audit the source code: the entire codebase is open source

Build Reproducibility

To build the source and inspect its reported version:

# Clone and build
git clone https://github.com/yvgude/lean-ctx.git
cd lean-ctx/rust
cargo build --release

# Compare with installed version
lean-ctx --version
./target/release/lean-ctx --version

Use the checksums attached to the relevant GitHub Release to check a downloaded artifact. Matching version strings does not prove byte-for-byte reproducibility or establish that a binary matches source.


Verifying Release Artifacts

Every release publishes SHA256SUMS and release-manifest.json, each signed with keyless Cosign by the release workflow (.sig and .pem next to the file).

  • lean-ctx update verifies both signatures against the pinned release-workflow identity, then the archive digest, and refuses the update on any failure.
  • install.sh and the npm package verify the archive against SHA256SUMS and abort when the checksum file, its entry for the archive, or a SHA-256 tool is missing, or when the digest does not match. There is no opt-out. They do not check the Cosign signature, so a tampered release whose SHA256SUMS was replaced too is only caught by the checks below.

To check a manual download yourself (replace vX.Y.Z with the release tag):

cosign verify-blob SHA256SUMS \
  --signature SHA256SUMS.sig --certificate SHA256SUMS.pem \
  --certificate-identity "https://github.com/yvgude/lean-ctx/.github/workflows/release.yml@refs/tags/vX.Y.Z" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
sha256sum --ignore-missing -c SHA256SUMS   # macOS: shasum -a 256 --ignore-missing -c SHA256SUMS

Releases built after GHSA-rxv5-4c3x-g4q6 also carry GitHub build-provenance attestations for every archive, wheel, SHA256SUMS and release-manifest.json:

gh attestation verify lean-ctx-aarch64-apple-darwin.tar.gz --repo yvgude/lean-ctx \
  --signer-workflow yvgude/lean-ctx/.github/workflows/release.yml

Disclosure Timeline

When vulnerabilities are reported:

  1. Day 0: Acknowledgment sent to reporter
  2. Day 7: Severity assessment completed
  3. Day 14: Patch development begins
  4. Day 30: Patch released + CVE filed (if applicable)
  5. Day 90: Public disclosure

Critical vulnerabilities (RCE, data exfiltration) are fast-tracked.


Known Residual Risks

TOCTOU (Time-of-Check to Time-of-Use)

Status: Mitigated on Unix; residual risk on Windows.

A race window exists between jail_path validation and the subsequent file operation. Mitigations in place: standard reads open with O_NOFOLLOW (Unix) and reject symlinks; ctx_edit additionally rejects symlinks on both its read and write paths (lstat pre-check on all platforms, O_NOFOLLOW on Unix) and re-verifies the file fingerprint (size/mtime/md5) immediately before writing. On Windows there is no O_NOFOLLOW equivalent, so the lstat pre-check is the only guard — it rejects symlinks and all NTFS reparse points (junctions, mount points) via pathutil::is_symlink_or_reparse, and read_file_nofollow applies the same lstat check before opening. The residual risk is the unavoidable check→open race window.

Recommendation for regulated environments: Run lean-ctx inside a container or VM where the filesystem is controlled and no untrusted processes can modify symlinks concurrently.

ctx_execute Sandbox Naming

Status: Documented limitation.

The ctx_execute tool provides timeout enforcement and output capping. OS isolation depends on sandbox_level, platform support, and the selected execution path. Configured level 1 uses Seatbelt on macOS or Landlock on Linux; unsupported platforms can fall back to level 0. Do not treat the tool name as proof of OS isolation. Inspect rust/src/core/sandbox.rs for the release in use.

Recommendation for regulated environments: Disable ctx_execute via role configuration (denied: ["ctx_execute"]) or run lean-ctx in a pre-existing container sandbox.

Shell Command Validation (REQ-57177, GH #391)

Status: Defense in depth — the agent's permission model remains the primary boundary. ctx_shell is not a sandbox.

ctx_shell and lean-ctx -c enforce, in both allowlist and blocklist-only mode:

  • a deny-by-default executable allowlist when configured (AST-segmented: every segment of a pipeline/compound command must be allowed),
  • eval/exec/source unconditionally blocked; $()/backticks blocked at command position,
  • interpreter inline-code blocking: bash -c, sh -c, python -c, node -e, … are rejected (including via delegation wrappers like env, timeout, xargs) — quoting a payload inside bash -c '…' does not bypass the file-write or allowlist checks because the interpreter call itself is refused,
  • file-write detection (>, >>, tee, heredoc-to-file, dd of=, curl -o/-O, wget to file) — output capture (>, >>, tee) may go to the session's project, allow_paths / extra_roots, write_allow_paths or a scratch path (never /, ~, an ancestor of ~ or a read_only_roots entry); downloads only to scratch paths and write_allow_paths; everything else belongs to the editor's native Write/Edit tools where the agent's permission UI governs them,
  • dangerous-flag blocking (git --upload-pack, tar --to-command, find -exec, awk system()), inline env hijack blocking (PATH=, LD_PRELOAD=, GIT_SSH_COMMAND=, …), and dangerous env-key filtering on the MCP env parameter,
  • no self-loosening (allowlist mode, the default): lean-ctx subcommands that widen its own guardrails — yolo, allow <cmd>, allow-path <dir>, trust, security open, security secrets off, config set of a security or path/allowlist key — are refused, so an agent cannot undo a refusal it just received. Listing, --remove, secure, untrust and security secrets on still run. The user runs the blocked commands in their own terminal (warn-only there, see below). ctx_execute is not covered — see the next paragraph.

Enforcement applies to the MCP path, hook-child mode and every non-interactive CLI invocation; an interactive human terminal gets a warning instead (LEAN_CTX_ALLOWLIST_WARN_ONLY=1 opts out explicitly). Cloud/infra mutation CLIs (terraform, kubectl, aws, …) are excluded from the default allowlist and require per-tool opt-in (lean-ctx allow <cmd>). Commands inside a substitution in an argument ($(…), backticks, <(…)/>(…)) are gated like top-level commands in every enforce-mode call. shell_strict_mode = true upgrades the remaining warn-only heuristic (pipe to a bare interpreter) to a hard block.

ctx_execute(language=shell) is deliberately NOT allowlisted (GH #905). The checks above gate ctx_shell and lean-ctx -c only. ctx_execute is the trusted script path: calling it is an explicit decision to write and run a script, the same decision a native Write plus bash script.sh would express, so re-running the allowlist there would only tax the sanctioned route. The consequence must be stated plainly rather than assumed: the two tools are one trust tier, not a boundary and a bypass. Any agent that can call ctx_execute has full shell reach no matter how shell_allowlist is configured — tightening the allowlist does not constrain it. Where that reach is unacceptable, deny the tool by role (denied: ["ctx_execute"]) or run the stack in an OS sandbox; those are the only controls that bind it.

Constructs the gate refuses (GHSA-rxv5-4c3x-g4q6 E). The command runs in the user's $SHELL, which may be bash, dash or zsh. Where these shells read the same text differently, or where the gate cannot tell which commands a construct runs, the command is refused rather than guessed at. Rewrite the command without the construct:

  • legacy $[ … ] arithmetic (use $(( … )));
  • zsh parameter flags ${(…)…} and bash prompt expansion ${x@P}, both of which can evaluate a value as code;
  • a ( attached to a word: zsh glob qualifiers (*(e:…:), *(+cmd)) and bash extended globs (@(…), !(…)); function heads f() and arrays a=(…) are fine;
  • a bare { argument (zsh brace bodies such as while c { … } or repeat n { … }), zsh short loops (for x (…) cmd), and a brace group followed by anything other than redirections ({ a; } b, { a } always { b });
  • hash -p and enable -f; a trap action is checked like a command;
  • a carriage return not followed by a line feed, and the Unicode line/paragraph separators U+2028/U+2029;
  • a here-document whose terminator line never appears;
  • constructs that bash, dash and zsh end at different places: $'…' with an escaped quote, a ' or { inside ${…}, << inside (( … )), and here-documents queued across a command-substitution boundary.

Assignments to variables that redirect which binary, library or startup code runs (LD_*, DYLD_*, BASH_ENV, ENV, PROMPT_COMMAND, PS4, SHELLOPTS, ZDOTDIR, GIT_CONFIG*, BASH_FUNC_*, pager and editor variables other than harmless values like cat, NODE_OPTIONS, PERL5OPT, RUBYOPT, …) are blocked anywhere in the assignment prefix and through export/declare/env/read/printf -v. PATH is blocked only as the first word of a command (PATH=… cmd); export PATH=… stays allowed.

Known limitation: arithmetic evaluation of variable contents. The gate is syntactic. bash evaluates array subscripts inside variable values at run time whenever a value is used in an arithmetic context, and that evaluation performs command substitution: x='a[$(cmd)]'; echo $((x)) runs cmd, as do let, [[ x -eq … ]], test -v, printf -v, unset and declare with such a value. The value can come from a quoted string or from a file read at run time, so no syntactic check can see it. This is one more reason the allowlist is not a sandbox: for untrusted input, use an OS sandbox or the agent's approval flow.

Explicitly out of scope: commands run with the invoking user's full privileges. Anything the user can do, an allowed command can do — cp/rsync can copy any file the OS lets the user read, package managers execute arbitrary install scripts, npm test runs project code. A blocklist cannot enumerate these; pretending otherwise would be security theater.

Rationale: Shell filters can be bypassed by a sufficiently creative attacker, so the agent's permission model (Claude Code allowlists, Cursor approval dialogs) remains the primary boundary — lean-ctx's allowlist is a second, independent layer, not a replacement.

Mitigation for untrusted agents: Use role-based denied: ["ctx_shell"] to disable shell access entirely, enable the deny-by-default allowlist with a minimal command set, and/or run the whole agent stack inside an OS sandbox (container, gVisor/Firecracker, bwrap, seccomp/AppArmor) — that is the correct layer for kernel-grade isolation.

PathJail TOCTOU Race (REQ-57178)

Status: Mitigated on Unix; residual risk on Windows.

A race window exists between jail_path validation and the subsequent file operation. Mitigations: symlink-following canonicalization before access, O_NOFOLLOW + symlink rejection on read paths (Unix), and symlink rejection on ctx_edit write paths (all platforms, lstat-based; on Windows this includes NTFS junctions and other reparse points). Home-level IDE config dirs (~/.cursor, ~/.claude, …) are excluded from the jail's allow-list by default (allow_ide_config_dirs opts in).

Windows file permissions: the Unix 0o600/0o700 tightening (cloud credentials, crash log) has no direct Windows equivalent; protection relies on the default NTFS ACL of the user profile (%USERPROFILE% is not readable by other non-admin users). Machines with custom ACLs on the profile directory should verify %USERPROFILE%\.lean-ctx inherits owner-only access.

Mitigation: For regulated environments: run lean-ctx inside a container where no untrusted processes can modify symlinks concurrently.

Cloud Server Database TLS (REQ-57188)

Status: Accepted risk — localhost-only by default.

The cloud server's PostgreSQL connection does not enforce TLS by default. This is acceptable because the cloud server is designed for localhost/loopback deployment where DB traffic does not traverse a network.

Mitigation for production: Set DATABASE_URL with ?sslmode=require or use a connection string that enforces TLS. When deployed behind a reverse proxy (nginx/Caddy), ensure TLS terminates before the DB.

HuggingFace Model Downloads

Status: Documented risk.

Embedding models for semantic search are downloaded from HuggingFace Hub. Verification is size-based heuristic only, not cryptographic (no SHA256 pinning for model files).

Recommendation for regulated environments: Pre-provision models manually from an internal mirror with signature verification. Set LEAN_CTX_EMBEDDING_MODEL_DIR to point to the pre-provisioned directory to skip downloads entirely.

Project-Scope Config Influences Injected Context (external audit, finding 4)

Status: Mitigated by Workspace Trust (selective gating + content-hash pin).

A cloned repository's .lean-ctx.toml is merged over the global config by Config::merge_local. That merge can raise security-sensitive settings — replace the shell allowlist, widen the path jail (allow_paths / extra_roots), repoint the proxy upstream, define command aliases, change rules_scope / rules_injection, or widen the exposed tool surface (tool_profile / tools_enabled / default_tool_categories). Opening an untrusted clone with an agent would let the repo silently weaken lean-ctx's own boundaries.

Mitigation (shipped): lean-ctx now applies a VS-Code-style Workspace Trust gate. For a workspace the user has not trusted, the security-sensitive overrides above are withheld (comfort knobs like compression/theme still apply) and a [SECURITY] warning is logged; lean-ctx doctor shows the state. Trust is granted explicitly with lean-ctx trust and pinned to BOTH the workspace path AND a content hash of .lean-ctx.toml, so editing the file after trust re-gates it (a "trust once, modify later" change cannot take effect silently). Headless/fleet use can opt in via LEAN_CTX_TRUST_WORKSPACE=1 or LEAN_CTX_TRUSTED_ROOTS.

Residual: Model-visible content lean-ctx injects (the static <!-- lean-ctx --> rules block, hook additionalContext, [VERIFY]/[HINT] suffixes) is itself auditable and not repo-controlled. Review a clone's .lean-ctx.toml before lean-ctx trust.

LLM Proxy is a Full MITM on API Traffic (external audit, finding 6)

Status: By design; loopback-bound and disabled by default.

When enabled, the optional LLM proxy (lean-ctx proxy) reads and rewrites every request body (compression, history pruning) and sees Authorization headers in cleartext — a concentrated sensitive-data surface. Any process able to reach the port, or a forwarding bug, would expose prompts, completions and API keys.

Mitigation: The proxy is disabled by default and binds to loopback (127.0.0.1) with an auto-generated auth token when enabled; keep it loopback-bound. The MCP ctx_* tools deliver compression savings without routing API traffic through any proxy — leave it disabled unless you need pay-as-you-go key forwarding.


Security Architecture for Enterprise Deployments

Recommended Configuration (Bank / Regulated)

LeanCTX splits global settings (config.toml) from capability policy (role files): config.toml does not define roles or a top-level [io] policy — per-session I/O limits live on the active role, which is selected via LEAN_CTX_ROLE.

1. Global hardening — ~/.lean-ctx/config.toml:

update_check_disabled = true   # no daily update check
path_jail = true               # keep the filesystem jail on (default)
path_jail_scope = "project"    # only the active project (default "home": all of ~ except protected zones)

[telemetry]
enabled = false                # explicitly disable telemetry
preference = "explicitly_disabled"

2. A locked-down role — ~/.lean-ctx/roles/bank.toml:

[role]
name = "bank"
description = "Locked-down role for regulated environments"

[tools]
denied = ["ctx_execute", "ctx_shell"]   # no code or shell execution

[io]
boundary_mode = "enforce"               # error (not warn) on boundary hits
allow_secret_paths = false              # never read .env / keys
allow_ignore_gitignore = false          # never scan .gitignore'd paths
allow_cross_project_search = false      # stay within this project

3. Activate the role where lean-ctx (or the MCP server) starts. The active role resolves in order env → project .lean-ctx/roles/ → global ~/.lean-ctx/roles/ → built-in:

export LEAN_CTX_ROLE=bank

Network Surface

Endpoint Purpose Disable
api.github.com/repos/yvgude/lean-ctx/releases/latest Update check (daily GET) update_check_disabled = true
api.leanctx.com Enabled telemetry (version, OS/arch, installation ID, client/setup categories, aggregate tool usage) lean-ctx telemetry off or DO_NOT_TRACK=1
huggingface.co Embedding model download Pre-provision models, set LEAN_CTX_EMBEDDING_MODEL_DIR
localhost:PORT Dashboard (local TCP) Don't start dashboard, or bind to loopback only
UDS socket Daemon IPC Permissions 0o600, owner-only access

Team Server Hardening (lean-ctx-enterprise)

The team server is part of lean-ctx-enterprise (ADR-023). When deployed:

  1. Token rotation: Rotate workspace tokens periodically. Tokens are stored in the team config.
  2. Scope minimization: Grant only necessary scopes per workspace token (e.g., read only, no shell).
  3. Network isolation: Bind the team server to an internal network interface, not 0.0.0.0.
  4. Audit log monitoring: Team server writes audit logs for all tool calls. Monitor for denied requests.
  5. JSON-RPC batch requests: Rejected by default to prevent scope bypass.

Supply Chain

  • cargo audit runs on every CI push (zero known CVEs tolerated).
  • cargo deny checks licenses and advisories.
  • Release signing: SHA256SUMS and release-manifest.json are Cosign-signed and every published file carries a GitHub build-provenance attestation (see Verifying Release Artifacts).
  • install.sh and npm postinstall.js verify downloaded archives against the SHA256SUMS release asset and fail closed when it is missing or does not match.
  • GitHub Actions uses pinned action versions with hash verification.

Contact


Last updated: 2026-10-19

There aren't any published security advisories