Skip to content

v1.81.2 Security Audit Fixes

jgravelle edited this page May 6, 2026 · 1 revision

v1.81.2 — Security & robustness audit fixes

A weekly audit found eight real problems. v1.81.2 fixes all of them.

What

The weekly security & architecture audit turned up one stdio-protocol corruption bug, four memory-leak / DoS surfaces on the HTTP transports, a regex hang vector in search_text, a hardening gap in the git probe, and a useful latency win on content-dump tools. Every finding from the audit is fixed in v1.81.2 — no findings deferred except a multi-PR refactor that's tracked as architectural debt. All 3645 tests green.


Why It Matters

For everyone

If you run jCodeMunch on a fresh machine and ask it to do anything that needs embeddings, the first call used to silently scribble three lines into the JSON-RPC channel and break the session. That's fixed. If you run jCodeMunch as an HTTP server, it now refuses to grow forever when clients misbehave.

For engineers

Finding Severity Fix
download_model() print() calls polluted stdout from the lazy _get_session() path High quiet=True on the auto-download branch; CLI prints redirected to stderr
Streamable-HTTP _sessions / _session_tasks dicts had no eviction Medium Cap at JCODEMUNCH_MAX_SESSIONS (1024) + idle sweeper at JCODEMUNCH_SESSION_IDLE_TIMEOUT (300 s); excess sessions get HTTP 503
Rate-limiter _buckets keyed by IP, never evicted Medium Empty buckets dropped on window-eviction; LRU cap at 10k IPs
SqliteStore._resolved_content_dirs was a class attribute Medium Moved to __init__ (instance-scoped)
search_text regex mode had no wall-clock budget Medium 2 s budget across the whole call; _meta.timed_out=true flag
resolve_repo._git_toplevel ran git in untrusted cwd with full env Low GIT_CONFIG_NOSYSTEM=1, GIT_CONFIG_GLOBAL=/dev/null, GIT_TERMINAL_PROMPT=0
redact_dict ran on every response, including raw-source tools Low Skipped for get_file_content, get_symbol_source, get_context_bundle
HTTP/SSE bound to non-loopback host without auth was silent Low Startup warning when JCODEMUNCH_HTTP_TOKEN unset and host is non-loopback

How

Usage

pip install -U jcodemunch-mcp

Two new env vars on the streamable-http transport:

# Reject new sessions once N are tracked (default 1024)
export JCODEMUNCH_MAX_SESSIONS=1024

# Evict sessions idle longer than N seconds (default 300)
export JCODEMUNCH_SESSION_IDLE_TIMEOUT=300

What comes back

search_text now reports when the regex budget tripped:

{
  "result_count": 17,
  "results": [...],
  "_meta": {
    "timing_ms": 2003.4,
    "files_searched": 142,
    "truncated": false,
    "timed_out": true
  }
}

Streamable-HTTP startup now logs a warning when bound publicly without auth:

WARNING: streamable-http bound to non-loopback host '0.0.0.0' without
JCODEMUNCH_HTTP_TOKEN — anyone on the network can drive this MCP server.
Set JCODEMUNCH_HTTP_TOKEN to require bearer auth.

Where the change lives

  • src/jcodemunch_mcp/embeddings/local_encoder.py — quiet auto-download; CLI prints to stderr
  • src/jcodemunch_mcp/server.py — HTTP session cap + idle sweeper; rate-limiter eviction; non-loopback warning; redaction skip-list
  • src/jcodemunch_mcp/storage/sqlite_store.py_resolved_content_dirs instance-scoped
  • src/jcodemunch_mcp/tools/search_text.py — regex wall-clock budget + timed_out meta
  • src/jcodemunch_mcp/tools/resolve_repo.py — neutralised git env on the toplevel probe

Connection to the jMRI Spec

The spec already requires deterministic ranking and bounded payload sizes; this release closes the operational corollaries — bounded process state and bounded query time. The HTTP-transport caps are the first piece of the operator-facing reliability surface that the next spec revision will formalise as a tier-1 conformance requirement.


jcodemunch-mcp on GitHub · 900+ stars

Clone this wiki locally