Skip to content

Security

github-actions[bot] edited this page Mar 23, 2026 · 20 revisions

Security

The MATLAB MCP Server implements a multi-layered security architecture to prevent misuse while keeping MATLAB accessible to AI agents. This document covers authentication, authorization, input validation, secure configuration, deployment best practices, and vulnerability reporting.

Authentication & Authorization

Transport-Level Access Control

The server supports two transport modes with different security implications:

Stdio Transport

  • Use case: Local development, single-user deployments
  • Authentication: Inherited from the client application (Claude Desktop, Cursor, etc.)
  • Authorization: No multi-user isolation; all code runs in the same MATLAB process
  • Recommendation: Suitable for personal/developer use only

SSE (Server-Sent Events) Transport

  • Use case: Multi-user team deployments, shared server scenarios
  • Authentication: Must be deployed behind a reverse proxy (nginx, Caddy, Traefik) with authentication layer
  • Authorization: Session-based; each user gets isolated temporary directories and workspace separation
  • Configuration flag: Set require_proxy_auth: true to acknowledge auth is configured
security:
  require_proxy_auth: true  # Required for SSE transport

server:
  transport: "sse"
  host: "127.0.0.1"        # Bind to localhost only; expose via proxy
  port: 8765

Warning: The server logs a startup warning if SSE is enabled without require_proxy_auth: true.

Session Management

Each user session receives:

  • Unique session ID (auto-generated UUID)
  • Isolated temp directory (./temp/{session_id}/) for file uploads/downloads
  • Separate workspace context via workspace_isolation setting
  • Automatic expiration after session_timeout seconds of inactivity (default 3600s)
  • Cleanup of temp files and job metadata on session end
sessions:
  max_sessions: 50              # Limit concurrent sessions
  session_timeout: 3600         # 1 hour idle timeout
  job_retention_seconds: 86400  # Keep completed job metadata for 24 hours
graph LR
    A["AI Agent<br/>(Claude, Cursor)"] -->|stdio or SSE| B["MCP Server"]
    B -->|Creates| C["Session ID"]
    C -->|Isolates| D["Temp Directory<br/>/temp/{session_id}/"]
    C -->|Isolates| E["MATLAB Workspace<br/>clear all between sessions"]
    D --> F["User Files<br/>uploads/downloads"]
    E --> G["User Variables<br/>functions, state"]
Loading

Input Validation & Sanitization

Function Blocklist (Code Security)

The server enforces a configurable blocklist of dangerous MATLAB functions. By default, these are blocked:

Function Risk Alternative
system() Execute arbitrary OS commands Use MATLAB System Control Toolbox, or request administrator approval
unix() Execute Unix commands Same as above
dos() Execute DOS/Windows commands Same as above
! Shell escape operator Same as above
eval() Execute arbitrary string as code Use evalc() (if allowed) or structured APIs
feval() Call function by name string Use function handles or structured APIs
evalc() Evaluate and capture output Use direct function calls where possible
evalin() Evaluate in caller/base workspace Use proper scoping/module structure
assignin() Assign variable in caller/base workspace Use return values or output arguments
perl() Execute Perl scripts Blocked for same reasons as system/unix/dos
python() Execute Python scripts Blocked for same reasons as system/unix/dos

Smart Scanning

The security validator strips string literals and comments before checking for blocked functions, preventing false positives:

% These are SAFE and will NOT trigger the blocklist:
disp('The operating system is great')    % "system" inside a string
% system('ls')                            % "system" inside a comment
msg = "unix-based systems are wonderful"; % "unix" inside a string
help system                               % "system" as help topic

% These WILL be blocked:
system('rm -rf /')                       % Actual system() call
x = eval('1 + 2')                        % Actual eval() call
feval('disp', 'hello')                   % Actual feval() call

Implementation Details

The validator:

  1. Removes all single/double-quoted string literals
  2. Removes all MATLAB comments (from % to end of line)
  3. Uses precompiled regex patterns to match function calls: func(), func arg, or shell escape !cmd
  4. Raises BlockedFunctionError if any match is found
  5. Can be disabled entirely with blocked_functions_enabled: false

Filename Sanitization

When uploading files, the server sanitizes filenames to prevent path traversal and injection attacks:

# Allowed characters: [a-zA-Z0-9._-]
# Rejected patterns:
"../../etc/passwd"      # Path traversal
"/etc/shadow"           # Absolute path
"file;rm -rf /"         # Shell injection
"file\x00.txt"          # Null byte injection

Valid filenames:

"data.csv"
"experiment-2024-01-15.mat"
"results_final_v2.xlsx"
"plot_sinwave.png"

Configuration:

security:
  max_upload_size_mb: 100      # Size limit (default 100MB)

Files are always uploaded to the session's isolated temp directory, not to arbitrary locations.

MATLAB Name Validation

When calling discovery tools (list_functions, get_help, list_toolboxes), the server validates MATLAB names to prevent command injection:

% Valid names (accepted):
fft, plot, Signal Processing, pkg.subpkg.func

% Invalid names (rejected):
;drop table, func;, !ls, @decorator, (expr)

Security Configuration

Blocked Functions Configuration

security:
  blocked_functions_enabled: true

  # Default blocklist (example; customize as needed):
  blocked_functions:
    - "system"
    - "unix"
    - "dos"
    - "!"
    - "eval"
    - "feval"
    - "evalc"
    - "evalin"
    - "assignin"
    - "perl"
    - "python"

To allow a blocked function (e.g., for a trusted use case):

  1. Remove it from the blocked_functions list, OR
  2. Disable blocking entirely: blocked_functions_enabled: false

Workspace Isolation

execution:
  workspace_isolation: true

When enabled (default), the server executes these commands at the start of each new session:

clear all;           % Remove all variables
clear global;        % Remove global variables
clear functions;     % Clear function cache
fclose all;          % Close all file handles
restoredefaultpath;  % Restore default MATLAB path

This ensures one user's variables, functions, and file handles don't leak to another user.

Upload Limits

security:
  max_upload_size_mb: 100      # Maximum file size (default 100MB)

Attempting to upload a file larger than this limit returns:

{
  "status": "failed",
  "error": {
    "type": "UploadError",
    "message": "File size (150 MB) exceeds maximum allowed (100 MB)"
  }
}

Session Limits

sessions:
  max_sessions: 50             # Maximum concurrent sessions

When the limit is reached, new session creation fails until idle sessions expire or are manually closed.

Best Practices for Secure Deployment

Personal / Developer Use

server:
  transport: "stdio"           # Single-user, no network exposure

security:
  blocked_functions_enabled: true  # Keep defaults
  require_proxy_auth: false        # N/A for stdio

execution:
  workspace_isolation: true    # Still recommended

Setup:

matlab-mcp --config config.yaml

Team Deployments (Shared Server)

server:
  transport: "sse"
  host: "127.0.0.1"            # Bind to localhost only
  port: 8765

security:
  blocked_functions_enabled: true
  require_proxy_auth: true     # Acknowledge auth is configured
  max_upload_size_mb: 500      # Adjust for team use

sessions:
  max_sessions: 20
  session_timeout: 7200        # 2 hours

execution:
  workspace_isolation: true

Setup (with nginx reverse proxy):

server {
    listen 8080 ssl;
    server_name matlab.internal.company.com;
    ssl_certificate /etc/ssl/certs/cert.pem;
    ssl_certificate_key /etc/ssl/private/key.pem;

    auth_basic "MATLAB Server";
    auth_basic_user_file /etc/nginx/.htpasswd;

    location / {
        proxy_pass http://127.0.0.1:8765;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Authorization $http_authorization;
        proxy_http_version 1.1;
        proxy_set_header Connection "upgrade";
        proxy_set_header Upgrade $http_upgrade;
    }
}

Then connect clients to https://matlab.internal.company.com:8080 instead of the raw MCP server.

Production Deployments

In addition to team best practices:

server:
  transport: "sse"
  host: "127.0.0.1"
  port: 8765
  log_level: "warning"         # Reduce log verbosity

security:
  blocked_functions_enabled: true
  require_proxy_auth: true
  max_upload_size_mb: 500      # Enforce reasonable limits

sessions:
  max_sessions: 100
  session_timeout: 3600        # 1 hour, enforced
  job_retention_seconds: 86400 # Purge old jobs

monitoring:
  enabled: true                # Enable metrics
  db_path: "/var/log/matlab-mcp/metrics.db"

pool:
  min_engines: 4
  max_engines: 16
  health_check_interval: 60    # Monitor engine health

Additional infrastructure:

  • TLS/SSL termination: Use a reverse proxy with valid certificates (Let's Encrypt)
  • Authentication: OAuth2, LDAP, or static htpasswd
  • Authorization: Role-based access control in the proxy (if needed)
  • Network: Isolate to internal network; do NOT expose to the internet without auth
  • Logging: Send server logs to a centralized log aggregation system
  • Monitoring: Use /health and /metrics endpoints for alerting
  • Backup: Regularly backup monitoring/metrics.db and config files
  • Updates: Subscribe to security advisories and update promptly

Restrictive Blocklist (Maximum Security)

For highly sensitive environments, extend the blocklist:

security:
  blocked_functions_enabled: true
  blocked_functions:
    - "system"
    - "unix"
    - "dos"
    - "!"
    - "eval"
    - "feval"
    - "evalc"
    - "evalin"
    - "assignin"
    - "perl"
    - "python"
    - "web"              # Prevent browser access
    - "delete"           # Prevent file deletion
    - "rmdir"            # Prevent directory deletion
    - "copyfile"         # Prevent file manipulation
    - "movefile"         # Prevent file manipulation
    - "feature"          # Prevent feature toggling
    - "ver"              # Prevent version/toolbox discovery (optional)

Data Flow & Architecture

graph TB
    Client["AI Agent<br/>(Claude, etc.)"]
    
    Client -->|MCP Protocol| Transport{Transport Mode}
    
    Transport -->|stdio| Local["Local Execution<br/>Single user"]
    Transport -->|SSE| Proxy["Reverse Proxy<br/>Auth + TLS"]
    
    Proxy -->|Authenticated<br/>Request| Server["MCP Server<br/>FastMCP"]
    Local --> Server
    
    Server -->|Extracts| SID["Session ID<br/>from context"]
    SID -->|Creates| TempDir["Temp Directory<br/>/temp/{sid}/"]
    
    Server -->|Validates| Code["Code"]
    Code -->|Check Blocklist| SVG["Security Validator"]
    Code -->|Sanitize Names| Names["Names"]
    
    SVG -->|Pass| Executor["Job Executor"]
    SVG -->|Fail| Error["BlockedFunctionError"]
    
    Executor -->|Acquire| Pool["Engine Pool<br/>Manager"]
    Pool -->|Engine +<br/>Workspace| Execute["Execute Code<br/>in MATLAB"]
    
    Execute -->|Capture| Output["stdout/stderr"]
    Execute -->|Return| Result["Job Result"]
    
    Result -->|Format| Formatter["Result Formatter"]
    Formatter -->|Truncate/Save| Response["MCP Response"]
    
    Response --> Client
    
    TempDir -->|Upload| Files["Session Files<br/>Isolated"]
    Files -->|Read| Read["read_script,<br/>read_image,<br/>read_data"]
    Read --> Response
    
    Error --> Response
Loading

Reporting Security Vulnerabilities

If you discover a security vulnerability in the MATLAB MCP Server:

  1. Do NOT open a public GitHub issue — this exposes the vulnerability to potential attackers
  2. Report privately by:
    • Emailing the maintainer at the address listed in glama.json or repository profile
    • Using GitHub's private vulnerability disclosure feature (if available)
  3. Include:
    • Description of the vulnerability
    • Steps to reproduce
    • Potential impact
    • Suggested fix (if you have one)
  4. Allow time for response — typically 7–14 days for a patch

Example vulnerability report:

Title: Blocklist bypass via string concatenation

Description: The security validator does not strip escaped quotes, allowing code like eval('x' + y) to bypass the eval() blocklist.

Steps to reproduce:

  1. Enable security validator
  2. Execute code: eval(['x = 1'])
  3. Expected: Blocked. Actual: Executed.

Suggested fix: Handle string concatenation patterns in the regex.

Summary

Layer Mechanism Configuration
Transport stdio (local) or SSE (networked) server.transport
Authentication Client app (stdio) or reverse proxy (SSE) security.require_proxy_auth
Authorization Session isolation + workspace clearing execution.workspace_isolation
Code Validation Function blocklist + smart scanning security.blocked_functions
Input Sanitization Filename validation, MATLAB name validation Built-in validators
Resource Limits Upload size, session count, execution timeout security.max_upload_size_mb, sessions.max_sessions, execution.sync_timeout
Session Management Unique IDs, temp directories, automatic cleanup sessions.session_timeout, execution.temp_cleanup_on_disconnect

Clone this wiki locally