-
Notifications
You must be signed in to change notification settings - Fork 0
Security
# Security
The MATLAB MCP Server includes multiple security layers to control code execution, manage authentication, and isolate user sessions while keeping MATLAB accessible to AI coding agents.
## Authentication and Authorization
### Bearer Token Authentication
When using HTTP-based transports (`streamablehttp` or legacy `sse`), the server enforces bearer token authentication to prevent unauthorized access.
```mermaid
graph LR
A["Agent Request<br/>Authorization: Bearer token"] --> B{Token Valid?}
B -->|Yes| C["Pass to MCP<br/>Execute tool"]
B -->|No| D["Return 401<br/>WWW-Authenticate: Bearer"]
E["MATLAB_MCP_AUTH_TOKEN<br/>Environment Variable"] --> BSource: Bearer token is read exclusively from the MATLAB_MCP_AUTH_TOKEN environment variable at server startup. No token should be stored in config.yaml.
Token Format: Opaque 64-character hexadecimal string (no JWT encoding required).
Bypassed Paths:
-
/health— Health check endpoint (always accessible for load balancers) -
OPTIONS *— CORS pre-flight requests (always allowed) -
stdiotransport — No authentication (by design; local, trusted context)
Use the built-in token generator:
matlab-mcp --generate-tokenOutput Example:
Generated bearer token:
a7f3e2c91d4b6f8e9a0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e
Export it for your platform:
# Linux/macOS (bash/zsh):
export MATLAB_MCP_AUTH_TOKEN="a7f3e2c91d4b6f8e9a0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e"
# Windows (Command Prompt):
set MATLAB_MCP_AUTH_TOKEN=a7f3e2c91d4b6f8e9a0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e
# Windows (PowerShell):
$env:MATLAB_MCP_AUTH_TOKEN="a7f3e2c91d4b6f8e9a0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e"
Then start the server:
matlab-mcp --transport streamablehttp
Agents connect by including the bearer token in the Authorization header:
# Claude Code
servers:
matlab:
command: "python"
args: ["-m", "matlab_mcp", "--transport", "streamablehttp"]
env:
MATLAB_MCP_AUTH_TOKEN: "your_64_char_token_here"
# Codex CLI (via HTTP)
url: "http://localhost:8765/mcp"
headers:
Authorization: "Bearer your_64_char_token_here"Timeout-Safe Comparison: The server uses hmac.compare_digest() for constant-time token comparison, preventing timing-based token oracle attacks.
The server logs a warning at startup if an HTTP-based transport is selected without the MATLAB_MCP_AUTH_TOKEN environment variable:
WARNING: No bearer token configured for HTTP transport.
Set MATLAB_MCP_AUTH_TOKEN=<token> to enable authentication.
Without auth, the server is vulnerable to unauthorized access.
| Transport | Auth Enforced | Bypass Paths |
|---|---|---|
stdio |
❌ No | N/A (local, trusted) |
streamablehttp |
✅ Yes |
/health, OPTIONS
|
sse (deprecated) |
✅ Yes |
/health, OPTIONS
|
When using HTTP transports, CORS headers are automatically included:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type, Accept
This allows browser-based agent UIs (e.g., Cursor's web panel) to connect without CORS errors.
The server uses smart pattern matching to detect and block dangerous MATLAB functions. By default, these functions are blocked:
| Function | Risk | Blocked By Default |
|---|---|---|
system(), unix(), dos()
|
Execute arbitrary OS commands | ✅ Yes |
! (shell escape operator) |
Execute shell commands | ✅ Yes |
eval(), feval(), evalc(), evalin()
|
Execute arbitrary code | ✅ Yes |
assignin() |
Modify caller's workspace | ✅ Yes |
perl(), python()
|
Execute external scripts | ✅ Yes |
web() |
Open browser (potential exfil) | ✅ Yes |
The validator strips string literals and comments before scanning, preventing false positives:
% ✅ SAFE — will NOT trigger the blocklist:
disp('system() is great') % "system" in string
% system('ls') % "system" in comment
msg = "unix-based systems"; % "unix" in string
help system % Harmless help call
% ❌ BLOCKED:
system('rm -rf /') % Actual system() call
eval(['x = ' num2str(user_input)]) % eval() with user datasecurity:
blocked_functions_enabled: true # Set false to disable entirely (NOT recommended)
blocked_functions: # Defaults shown; customize as needed
- "system"
- "unix"
- "dos"
- "!"
- "eval"
- "feval"
- "evalc"
- "evalin"
- "assignin"
- "perl"
- "python"
- "web"Filenames are sanitized to prevent path traversal and injection attacks:
| Attack | Example | Blocked | Why |
|---|---|---|---|
| Path traversal | ../../etc/passwd |
✅ Yes |
.. stripped; rejected |
| Absolute paths | /etc/passwd |
✅ Yes |
/ disallowed |
| Special chars | file;rm -rf / |
✅ Yes | Only [a-zA-Z0-9._-] allowed |
| Unicode tricks | файл.m |
✅ Yes | ASCII only |
Allowed Characters: Letters, digits, dots (.), underscores (_), hyphens (-)
% ✅ ACCEPTED:
read_script("signal_analysis.m")
upload_data("train_data_v2.csv")
read_image("plot_2024-01-15.png")
% ❌ REJECTED:
read_script("../../etc/passwd") % Path traversal
upload_data("/tmp/malicious.mat") % Absolute path
delete_file("data;rm -rf /") % Shell injection attemptAll file operations are scoped to the session's temporary working directory:
execution:
workspace_isolation: true # Enable session-scoped temp dirs (default: true)
max_upload_size_mb: 100 # Reject uploads exceeding this sizeThe server warns if sensitive keys appear in config.yaml at startup:
# ❌ DON'T DO THIS (will trigger warning):
security:
auth_token: "a7f3e2c91d4b6f8e9a0c1d2e3f4a5b6c" # Warning: token in config!
# ✅ DO THIS (no warning):
# Set MATLAB_MCP_AUTH_TOKEN environment variable insteadStartup Warning Example:
WARNING: Sensitive keys detected in config.yaml:
- auth_token
These should NOT be stored in config files. Use environment variables instead:
export MATLAB_MCP_AUTH_TOKEN="..."
All configuration values support MATLAB_MCP_* environment variable overrides, which take precedence over config.yaml:
# Override from command line
export MATLAB_MCP_AUTH_TOKEN="your_token"
export MATLAB_MCP_SERVER_TRANSPORT="streamablehttp"
export MATLAB_MCP_SECURITY_BLOCKED_FUNCTIONS_ENABLED="true"
# Then start the server (config.yaml values are overridden)
matlab-mcp --config my_config.yamlWhen enabled, certain operations pause and request human approval via the MCP elicitation protocol before executing.
hitl:
enabled: false # Master switch (default: disabled)
protected_functions: # Functions requiring approval when called
- "fopen"
- "delete"
protect_file_ops: false # Require approval for upload/delete?
all_execute: false # Require approval for ALL code execution?| Operation | Enabled By | Example Flow |
|---|---|---|
| Protected function execution |
hitl.enabled: true + function in protected_functions
|
Code calls delete() → server pauses → requests approval → resumes on "accept" |
| File upload/delete | hitl.protect_file_ops: true |
Agent calls upload_data() → server pauses → human reviews filename/size → approves or denies |
| All code execution | hitl.all_execute: true |
Any execute_code call → server pauses → human reviews code → approves or denies |
% Config: hitl.protected_functions = ["delete"]
delete('old_file.txt') % ⏸ Paused: "Approve deletion of old_file.txt?"
% Human clicks "approve" in client UI
% ✅ Execution resumes; file deletedAgents (or humans in the loop) can:
- Accept — Proceed with the operation
- Decline — Deny the operation; return error to agent
- Cancel — Cancel the operation without error
Each session gets its own isolated MATLAB workspace. Sessions don't share:
- Variables
- Functions (beyond built-in)
- File handles
- Current directory
- Path (toolbox paths)
execution:
workspace_isolation: true # Clear workspace between tool calls (default: true)When workspace_isolation: true, the server runs at the start of each session:
clear all
clear global
clear functions
fclose all
restoredefaultpathEach session has its own temporary working directory:
/tmp/matlab_mcp_sessions/
├── session_abc123/ # User A
│ ├── upload1.mat
│ ├── results.csv
│ └── ...
├── session_def456/ # User B
│ ├── data.xlsx
│ └── ...
└── ...
Files uploaded by one user are not visible to another. When a session times out or is destroyed, its temp directory is deleted.
sessions:
max_sessions: 10 # Maximum concurrent sessions
session_timeout_seconds: 3600 # Idle timeout (1 hour default)
job_retention_seconds: 86400 # Keep job history 24 hours
temp_cleanup_on_disconnect: true # Delete temp files on session end (default: true)The server logs security-relevant events to stdout/file:
| Event Type | Logged | Example |
|---|---|---|
| Blocked function detected | ✅ Yes | SECURITY: Blocked 'system()' call in code |
| Invalid auth token | ✅ Yes | AUTH: Invalid bearer token from 127.0.0.1 |
| File path traversal attempt | ✅ Yes | SECURITY: Path traversal rejected: ../../etc/passwd |
| Session timeout | ✅ Yes | SESSION: Closed session session_abc123 (idle 1h) |
| HITL approval event | ✅ Yes | HITL: Approved execution of protected function delete() |
The /health endpoint exposes server status without authentication:
curl http://localhost:8765/healthResponse:
{
"status": "healthy",
"uptime_seconds": 3600,
"active_jobs": 2,
"active_sessions": 3,
"engine_pool": {"available": 5, "busy": 3, "total": 8},
"error_rate_percent": 0.5
}The /dashboard endpoint (HTTP transport only) provides real-time metrics:
http://localhost:8765/dashboard
Tracks:
- Engine pool utilization
- Job throughput and latency
- Error rates and failure types
- Session activity
- System resource usage
server:
transport: "stdio" # Local only; no auth needed
security:
blocked_functions_enabled: true # Keep default blocklist
workspace_isolation: trueSecurity Posture: ✅ Low risk (trusted local agent only)
server:
transport: "streamablehttp"
host: "127.0.0.1" # Bind to localhost
port: 8765
security:
blocked_functions_enabled: true
workspace_isolation: true
sessions:
max_sessions: 5
session_timeout_seconds: 3600
hitl:
enabled: true # Require approval for sensitive ops
protected_functions:
- "delete"
- "fopen"
protect_file_ops: trueSetup:
- Generate a token:
matlab-mcp --generate-token - Export to all team members:
export MATLAB_MCP_AUTH_TOKEN="..." - Each agent/IDE configures the token in their MCP client settings
- Server logs all operations for audit trail
Security Posture: ✅ Medium (auth + workspace isolation + approval gates)
server:
transport: "streamablehttp"
host: "0.0.0.0" # Exposed via reverse proxy below
port: 8765
stateless_http: true # No session affinity (load-balanced)
security:
blocked_functions_enabled: true
workspace_isolation: true
max_upload_size_mb: 50 # Tighter limits
sessions:
max_sessions: 100
session_timeout_seconds: 1800 # 30 min (shorter for shared infra)
hitl:
enabled: true
protected_functions:
- "delete"
- "fopen"
- "system" # Even if not blocked, require approval
- "evalin"
protect_file_ops: true
all_execute: false # Set true if you want to review ALL codeRequired Reverse Proxy Setup (nginx example):
server {
listen 443 ssl http2;
server_name matlab-mcp.company.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# Authentication at reverse proxy level
auth_request /oauth2/auth;
error_page 401 = /oauth2/sign_in;
location / {
proxy_pass http://127.0.0.1:8765;
proxy_set_header Authorization $http_authorization;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto https;
}
}Security Posture: ✅ High (TLS + reverse proxy auth + bearer tokens + workspace isolation + approval gates + audit logging)
If you discover a security vulnerability in the MATLAB MCP Server:
- Do NOT open a public GitHub issue — this discloses the vulnerability to attackers
- Email security details to: [project maintainer or security contact]
-
Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Any suggested fixes
The maintainers will acknowledge receipt within 48 hours and work with you on a fix. Coordinated disclosure timelines typically allow 90 days before public disclosure.
The legacy SSE transport is deprecated in v2.0 and will be removed in v3.0. It has inherent security limitations:
- Requires a reverse proxy with authentication (no built-in auth)
- Cannot enforce TLS without a proxy
- Session cookies are fragile over long-lived connections
Migration Path: Use streamablehttp transport instead (see Configuration).
The security validator uses regex-based pattern matching to detect blocked functions. While it handles most common cases (including string/comment stripping), it is not a formal AST-based code parser. Sophisticated obfuscation might evade detection.
Recommendation: If security is critical, run the server on a restricted-access machine or behind a proxy that enforces additional application-level controls.
The blocklist covers the most dangerous MATLAB functions, but new threats may emerge. Regularly review and update config.yaml as needed.
Custom Blocklist Example:
security:
blocked_functions:
- "system"
- "unix"
- "dos"
- "!"
- "eval"
- "feval"
- "evalc"
- "evalin"
- "assignin"
- "perl"
- "python"
- "web"
- "importdata" # Add your own here
- "xlsread" # e.g., if your org forbids certain functions- MCP Specification
- FastMCP Security Documentation
- OWASP: Code Injection
- MATLAB Security Best Practices (in your MATLAB documentation)