VAITP Dataset

← Back to the dataset

CVE-2026-29787

mcp-memory-service exposes system info via unauthenticated health endpoint.

  • CVSS 5.3
  • CWE-200
  • Information Leakage
  • Remote

mcp-memory-service is an open-source memory backend for multi-agent systems. Prior to version 10.21.0, the /api/health/detailed endpoint returns detailed system information including OS version, Python version, CPU count, memory totals, disk usage, and the full database filesystem path. When MCP_ALLOW_ANONYMOUS_ACCESS=true is set (required for the HTTP server to function without OAuth/API key), this endpoint is accessible without authentication. Combined with the default 0.0.0.0 binding, this exposes sensitive reconnaissance data to the entire network. This issue has been patched in version 10.21.0.

CVSS base score
5.3
Published
2026-03-07
OWASP
A01 Broken Access Control
Orthogonal defect classification
Checking
Code defect classification
Missing Check
Category
Information Leakage
Subcategory
Information Disclosure
Accessibility scope
Remote
Impact
Information Disclosure
Affected component
mcp-memory-s
Fixed by upgrading
Yes

Solution

Upgrade mcp-memory-service to version 10.21.0 or later.

Vulnerable code sample

import os
import sys
import platform
import psutil
from flask import Flask, jsonify

# --- Vulnerable Code Simulation ---
# This code represents the state of the application BEFORE the patch for CVE-2026-29787.
# The vulnerability lies in the unauthenticated exposure of the /api/health/detailed endpoint
# when the application is configured to allow anonymous access.

# Assume MCP_ALLOW_ANONYMOUS_ACCESS is set to "true" via an environment variable.
# For this demonstration, we'll proceed as if this condition is met.

app = Flask(__name__)

# This would typically be loaded from a configuration file or environment.
# Exposing this is a key part of the vulnerability.
DATABASE_FILESYSTEM_PATH = "/var/lib/mcp/data/memory_database.db"

@app.route('/api/health/detailed', methods=['GET'])
def get_detailed_health():
    """
    VULNERABLE ENDPOINT: Exposes detailed system and application information
    without any authentication or authorization checks.
    """
    try:
        # Gather sensitive system information
        os_version = platform.platform()
        python_version = sys.version
        cpu_count = os.cpu_count()
        
        # Memory usage
        memory = psutil.virtual_memory()
        memory_total_gb = round(memory.total / (1024 ** 3), 2)
        memory_used_gb = round(memory.used / (1024 ** 3), 2)
        memory_percent = memory.percent

        # Disk usage for the root partition
        disk = psutil.disk_usage('/')
        disk_total_gb = round(disk.total / (1024 ** 3), 2)
        disk_used_gb = round(disk.used / (1024 ** 3), 2)
        disk_percent = disk.percent

        # Construct the detailed response payload
        detailed_info = {
            "status": "ok",
            "system_details": {
                "os_version": os_version,
                "python_version": python_version,
                "cpu_count": cpu_count,
                "memory": {
                    "total_gb": memory_total_gb,
                    "used_gb": memory_used_gb,
                    "usage_percent": memory_percent
                },
                "disk": {
                    "total_gb": disk_total_gb,
                    "used_gb": disk_used_gb,
                    "usage_percent": disk_percent
                }
            },
            "database": {
                "path": DATABASE_FILESYSTEM_PATH  # Leaking the full filesystem path
            }
        }
        return jsonify(detailed_info), 200

    except Exception as e:
        return jsonify({"status": "error", "message": str(e)}), 500

if __name__ == '__main__':
    # The default binding to '0.0.0.0' makes the server accessible from the entire network.
    # Combined with the lack of authentication on the detailed health endpoint, this
    # exposes sensitive reconnaissance data.
    print("Starting vulnerable mcp-memory-service...")
    print("WARNING: MCP_ALLOW_ANONYMOUS_ACCESS is enabled.")
    print("WARNING: The /api/health/detailed endpoint is exposed without authentication.")
    app.run(host='0.0.0.0', port=8000)

Patched code sample

import os
import sys
import psutil
import shutil
from typing import Optional

from fastapi import FastAPI, Depends, Header, HTTPException, status
from pydantic import BaseModel, Field

# --- Configuration ---
# In a real application, this would be loaded from environment variables.
ADMIN_API_KEY = "fixed-secret-api-key-required-for-details"
DB_FILESYSTEM_PATH = "/var/data/mcp/memory.db"

# This represents the vulnerable setting. Even if true, the fix ensures the
# sensitive endpoint remains protected.
MCP_ALLOW_ANONYMOUS_ACCESS = True


# --- FastAPI Application Setup ---
# This code represents the patched version (e.g., 10.21.0 or later).
app = FastAPI(
    title="MCP Memory Service (Patched)",
    version="10.21.0",
)


# --- Pydantic Models for Response Payloads ---
class BasicHealthResponse(BaseModel):
    status: str = "ok"

class DetailedHealthResponse(BaseModel):
    os_version: str
    python_version: str
    cpu_count: int
    memory_total_gb: float
    disk_total_gb: float
    disk_free_gb: float
    database_path: str


# --- Authentication Dependency (THE FIX) ---
# This dependency function is the core of the fix. It is applied to any
# endpoint that must be protected, ensuring an authorization check occurs
# before the endpoint's logic is executed.
async def require_admin_authentication(x_admin_api_key: Optional[str] = Header(None)):
    """
    Checks for a valid admin API key in the request headers.
    If the key is missing or incorrect, it raises an HTTP 401 Unauthorized error.
    """
    if not x_admin_api_key or x_admin_api_key != ADMIN_API_KEY:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="A valid X-Admin-API-Key header is required for this endpoint",
        )


# --- API Endpoints ---

@app.get(
    "/api/health",
    tags=["Health"],
    summary="Public Basic Health Check",
    response_model=BasicHealthResponse
)
async def get_basic_health():
    """
    A basic, non-sensitive health check that can remain public.
    This endpoint does not have the authentication dependency.
    """
    return {"status": "ok"}


@app.get(
    "/api/health/detailed",
    tags=["Health"],
    summary="Protected Detailed System Health Information",
    response_model=DetailedHealthResponse,
    # VULNERABILITY FIX: The `dependencies` list now includes the
    # `require_admin_authentication` check. This prevents unauthenticated
    # access to the sensitive information returned by this endpoint.
    dependencies=[Depends(require_admin_authentication)],
)
async def get_detailed_health():
    """
    Returns detailed and sensitive system information. Access is now restricted
    to authenticated users only, resolving the information disclosure vulnerability.
    """
    mem = psutil.virtual_memory()
    disk = shutil.disk_usage("/")
    try:
        # os.uname() is not available on Windows
        os_info = f"{sys.platform} {os.uname().release}"
    except AttributeError:
        os_info = f"{sys.platform} {sys.getwindowsversion().major}.{sys.getwindowsversion().minor}"

    return DetailedHealthResponse(
        os_version=os_info,
        python_version=sys.version,
        cpu_count=os.cpu_count() or 0,
        memory_total_gb=round(mem.total / (1024 ** 3), 2),
        disk_total_gb=round(disk.total / (1024 ** 3), 2),
        disk_free_gb=round(disk.free / (1024 ** 3), 2),
        database_path=DB_FILESYSTEM_PATH,
    )

Cite this entry

@misc{vaitp:cve202629787,
  title        = {{mcp-memory-service exposes system info via unauthenticated health endpoint.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-29787},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-29787/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::