Security Considerations for Deploying Code-Graph-RAG in Production

Deploy Code-Graph-RAG securely by binding the Memgraph and Qdrant services to loopback interfaces, disabling hybrid front-ends for untrusted repositories, enabling bearer-token authentication for the MCP server, and storing API keys in restricted environment files with 600 permissions.

Code-Graph-RAG builds knowledge graphs of codebases using Tree-sitter parsers and stores them in a local Memgraph instance, with optional vector embeddings in Qdrant. When moving from local experimentation to production environments, understanding the trust boundaries and threat model is essential to prevent unauthorized network access, code execution, and data exfiltration. This guide covers the security architecture, threat model, and hardening steps required for a safe deployment.

Core Security Architecture

Code-Graph-RAG integrates several components, each with specific security concerns and mitigations defined in docs/architecture/security.md:

  • Tree-sitter Parsing reads source files and produces ASTs. Pure parsers never execute repository code, but the C++ (CPP_FRONTEND=hybrid) and C# (CSHARP_FRONTEND=auto) front-ends invoke external toolchains that may run parts of the repository under the current user's privileges. For untrusted repositories, explicitly set CSHARP_FRONTEND=treesitter to avoid invoking the Roslyn compiler.

  • Memgraph Graph Store holds the structural graph locally. By default, Docker exposes port 7687 on all network interfaces, making it reachable from any host on the same network if not properly bound.

  • Qdrant Vector Store stores embeddings for semantic search. Like Memgraph, it publishes port 6333 to the host network by default and requires the same loopback binding hardening.

  • LLM and Embedding Providers send code snippets and queries to embedding services. All external traffic uses TLS enforced via httpx. By default, the system uses a local UniXcoder model; external providers like OpenAI are only contacted when CGR_EMBEDDING_PROVIDER=openai is explicitly set.

  • MCP Server provides an HTTP API for agents. It binds to 127.0.0.1 by default. Binding to a non-loopback address requires setting the MCP_HTTP_AUTH_TOKEN environment variable and implementing bearer-token validation.

  • Agent Tools (CLI) execute shell commands and edit files on user request. The default mode screens commands against an allowlist and blocks destructive paths. A "YOLO" mode exists to disable this protection but is off by default.

  • XML and Other Parsers use defusedxml to safely parse XML from target projects, disabling dangerous features that could lead to entity-expansion attacks.

Threat Model and Trust Boundaries

The security model defines four primary trust boundaries that operators must enforce:

  1. Untrusted Repository Input – The repository being indexed is treated as hostile input. While pure Tree-sitter parsers cannot execute code, hybrid front-ends for C++ and C# may invoke toolchains that run repository build scripts under the current user's privileges.

  2. Local Service Exposure – Memgraph and Qdrant run in Docker containers with ports published to the host network. Without explicit loopback binding, these services are reachable from any host on the same network, creating an unauthenticated access vector.

  3. LLM and Embedding Provider Boundary – When configured to use remote providers, code snippets travel over TLS. API keys are supplied via environment variables (.env) and are never stored inside the graph database.

  4. MCP Server Boundary – By default, the server only listens on 127.0.0.1. If exposed to the network, authentication via a bearer token is mandatory.

The security model guarantees that credentials never appear in the graph and that network-exposed services are unauthenticated by default, requiring the operator to implement additional network controls or authentication layers.

Production Hardening Recommendations

Implement these controls to secure a production deployment:

  • Restrict Docker Port Bindings – Prevent unauthenticated remote access by binding Memgraph and Qdrant to localhost only. Use -p 127.0.0.1:7687:7687 for Memgraph and -p 127.0.0.1:6333:6333 for Qdrant. This addresses the exposure tracked in issue #1012.

  • Disable Hybrid Front-ends for Untrusted Code – Hybrid front-ends may execute build scripts. Export CSHARP_FRONTEND=treesitter and CPP_FRONTEND=treesitter before running cgr start to force pure parsing mode.

  • Run the Daemon Stack Behind a Firewall – Limit exposure to internal networks only by using Docker's private bridge networks or restricting traffic to trusted IP ranges via host-level firewalls.

  • Secure LLM API Keys – Store keys in a .env file with restrictive permissions (chmod 600 .env) and never commit this file to version control. The codebase_rag/stack/manager.py file handles daemon lifecycle commands and respects these environment variables.

  • Enable MCP Authentication – When binding the MCP server to a non-loopback address, set MCP_HTTP_AUTH_TOKEN=<strong-token> and configure clients to send the bearer token in the HTTP Authorization header.

  • Audit Dependencies – Supply-chain attacks are mitigated by pinned dependencies in uv.lock. The project runs OSV-Scanner and Dependabot checks via CI. Keep uv.lock updated and verify checksums.

  • Use Signed Releases – Verify release artifacts with Sigstore to guarantee integrity. Use cosign verify-blob with the provided public key for the release tarball.

  • Apply Least-Privilege Runtime – Run the daemon under a dedicated system user with limited permissions. Start the Docker stack with that user's UID to minimize blast radius.

Configuration Examples

Apply these hardening configurations in your production environment:


# 1. Restrict Docker port bindings to localhost (loopback)

docker run -d \
  --name memgraph \
  -p 127.0.0.1:7687:7687 \
  memgraph/memgraph

docker run -d \
  --name qdrant \
  -p 127.0.0.1:6333:6333 \
  qdrant/qdrant

# 2. Disable C# and C++ hybrid front-ends for untrusted repos

export CSHARP_FRONTEND=treesitter
export CPP_FRONTEND=treesitter
cgr start --repo-path /path/to/repo --update-graph

# 3. Secure MCP server with token authentication

export MCP_HTTP_AUTH_TOKEN="s3cr3t-token-$(uuidgen)"
cgr daemon up

# To bind to a specific interface with auth:

# cgr daemon up --bind 0.0.0.0 --token "$MCP_HTTP_AUTH_TOKEN"

# 4. Store API keys in a protected .env file

cat > .env <<EOF
OPENAI_API_KEY=sk-********************
MCP_HTTP_AUTH_TOKEN=s3cr3t-token-$(uuidgen)
EOF
chmod 600 .env

# 5. Verify a signed release artifact (example for version 0.0.484)

cosign verify-blob --key cosign.pub code-graph-rag-0.0.484.tar.gz

Key Implementation Files

Reference these source files to understand and configure the security posture:

Summary

  • Bind Memgraph (port 7687) and Qdrant (port 6333) to 127.0.0.1 to prevent unauthenticated remote access.
  • Set CSHARP_FRONTEND=treesitter and CPP_FRONTEND=treesitter when indexing untrusted repositories to avoid arbitrary code execution via build toolchains.
  • Protect API keys in .env files with chmod 600 permissions, and enable MCP_HTTP_AUTH_TOKEN when exposing the MCP server beyond localhost.
  • Verify release integrity using Sigstore cosign and maintain dependency hygiene by auditing the pinned uv.lock file.

Frequently Asked Questions

Does Code-Graph-RAG execute the code it indexes?

Pure Tree-sitter parsers do not execute code, but the C++ and C# hybrid front-ends (CPP_FRONTEND=hybrid, CSHARP_FRONTEND=auto) may invoke external toolchains that run repository build scripts under the current user's privileges. To prevent execution, set these environment variables to treesitter before running cgr start.

How do I prevent remote access to the Memgraph database?

By default, Docker publishes port 7687 on all interfaces. Bind it to loopback only by using the flag -p 127.0.0.1:7687:7687 when starting the container. The project tracks a change to make this the default behavior in issue #1012.

Is data sent to external LLM providers encrypted?

Yes, all HTTP traffic to external providers uses TLS via the httpx library. However, be aware that sensitive code leaves your machine when using external providers. The default configuration uses a local UniXcoder model; external providers are only contacted when CGR_EMBEDDING_PROVIDER=openai is explicitly configured.

How does the MCP server handle authentication?

By default, the MCP server binds to 127.0.0.1 and requires no authentication. If you bind it to a non-loopback address using --bind, you must set the MCP_HTTP_AUTH_TOKEN environment variable. Clients must then include the token as a Bearer token in the Authorization HTTP header, as enforced by the logic in codebase_rag/cli.py.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →