# How CBM_ALLOWED_ROOT Restricts Indexing in Multi-Tenant Environments

> Learn how CBM_ALLOWED_ROOT restricts indexing in multi-tenant environments. This environment variable prevents untrusted callers from accessing unauthorized directories, securing your codebase.

- Repository: [Martin Vogel/codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp)
- Tags: how-to-guide
- Published: 2026-07-12

---

**CBM_ALLOWED_ROOT is an environment variable that confines repository indexing to a specific filesystem boundary, preventing untrusted callers from accessing arbitrary paths outside the tenant's designated directory.**

The `codebase-memory-mcp` service provides Model Context Protocol (MCP) capabilities for indexing code repositories, but when operating in multi-tenant deployments or with untrusted AI agents, it must block attempts to index sensitive host paths. By setting `CBM_ALLOWED_ROOT`, administrators can enforce strict filesystem isolation, ensuring that each tenant's indexing operations remain confined to their allocated directory.

## The Security Mechanism Behind CBM_ALLOWED_ROOT

When the `index_repository` command is invoked, the implementation in **[`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c)** performs a four-step validation process before any graph or database operations begin.

### Path Canonicalization and Resolution

First, the supplied `repo_path` undergoes normalization to resolve absolute paths and eliminate symbolic links. The function `canonicalize_repo_path_if_exists` converts relative paths and components like `../` into a clean, absolute form, preventing attackers from using path traversal sequences to escape intended boundaries.

### Environment Variable Enforcement

Second, the code retrieves the guard variable:

```c
const char *allowed_root = getenv("CBM_ALLOWED_ROOT");

```

If `CBM_ALLOWED_ROOT` is set and non-empty, the system enters restricted mode and validates the requested path against this root.

### The cbm_path_within_root Validation

Third, the helper function **`cbm_path_within_root`** (implemented in **[`src/util/path.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/util/path.c)**) performs a secure prefix comparison. This function canonicalizes both the allowed root and the requested repository path, then verifies that the repository path is a descendant of the allowed root directory.

### Rejection of Out-of-Scope Requests

Finally, if the validation fails, the command returns an error before any pipeline creation occurs. As seen in lines 4819-4826 of [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c), the implementation returns:

```c
if (allowed_root && allowed_root[0] && repo_path &&
    !cbm_path_within_root(allowed_root, repo_path)) {
    return cbm_mcp_text_result("repo_path is outside the allowed root", true);
}

```

This ensures that no graph or database is touched for disallowed paths, providing fail-safe isolation.

## Multi-Tenant Deployment Configuration

In a multi-tenant environment, each tenant receives a dedicated workspace directory. By exporting `CBM_ALLOWED_ROOT` before starting the MCP service, you can isolate tenant operations completely.

### Configuration Example

To restrict a service instance to a specific tenant:

```bash

# Set the boundary for tenant-42

export CBM_ALLOWED_ROOT=/srv/mcp/tenant-42

# Start the service

./codebase-memory-mcp

```

### Valid and Invalid Path Examples

With the above configuration, the service behaves as follows:

```bash

# Permitted: Path within the allowed root

codebase-memory-mcp index_repository repo_path=/srv/mcp/tenant-42/project1

# Result: Indexing proceeds normally

# Blocked: Path outside the allowed root

codebase-memory-mcp index_repository repo_path=/etc

# Result: Error - "repo_path is outside the allowed root"

# Blocked: Path traversal attempt

codebase-memory-mcp index_repository repo_path=/srv/mcp/tenant-42/../../../etc/passwd

# Result: Error - canonicalized path resolves outside allowed root

```

## Implementation Details and Code References

The restriction logic resides in the MCP command handler at **[`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c)**, with the core path validation implemented in **[`src/util/path.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/util/path.c)**. The `cbm_path_within_root` function handles the secure comparison, ensuring that both paths are canonicalized before checking the prefix relationship.

This mechanism is documented in the **[`docs/CONFIGURATION.md`](https://github.com/DeusData/codebase-memory-mcp/blob/main/docs/CONFIGURATION.md)** reference guide and summarized in the repository's **[`README.md`](https://github.com/DeusData/codebase-memory-mcp/blob/main/README.md)**, providing administrators with clear guidance on securing multi-tenant deployments.

## Summary

- **CBM_ALLOWED_ROOT** acts as a filesystem boundary guard that prevents indexing outside designated directories.
- The validation occurs in **[`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c)** before any graph or database operations, ensuring fail-safe rejection of unauthorized paths.
- The **`cbm_path_within_root`** helper in **[`src/util/path.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/util/path.c)** performs secure canonicalization and prefix checking to prevent bypasses via symbolic links or path traversal sequences.
- In multi-tenant deployments, setting `CBM_ALLOWED_ROOT` to tenant-specific directories (e.g., `/srv/mcp/tenant-123`) ensures complete isolation between tenants and protects host system files.

## Frequently Asked Questions

### What happens if CBM_ALLOWED_ROOT is not set?

When the environment variable is unset or empty, the `codebase-memory-mcp` service operates without filesystem restrictions, allowing indexing of any path accessible to the process. This mode is suitable for trusted single-tenant environments but should never be used when handling requests from untrusted sources or in multi-tenant configurations.

### Can symbolic links bypass the CBM_ALLOWED_ROOT restriction?

No. The implementation calls `canonicalize_repo_path_if_exists` on the requested path before validation, which resolves symbolic links to their actual targets. The `cbm_path_within_root` function then compares the canonicalized absolute paths, ensuring that a symlink pointing outside the allowed root is correctly identified and rejected.

### How does this protect against path traversal attacks?

The combination of path canonicalization and the `cbm_path_within_root` prefix check prevents traversal sequences like `../` from escaping the allowed directory. Even if a caller supplies a path like `/srv/mcp/tenant-42/../../../etc/passwd`, the canonicalization resolves this to `/etc/passwd`, which fails the descendant check against `/srv/mcp/tenant-42`.

### Is CBM_ALLOWED_ROOT checked for read operations or only indexing?

The analysis focuses on the `index_repository` MCP command, where the check is explicitly implemented in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c). The restriction applies to repository indexing operations, preventing unauthorized filesystem traversal during the ingestion phase. Administrators should verify whether additional MCP commands in their specific deployment version enforce the same restriction for read operations by consulting the current source code.