Files
Infraviewer/MCP_SECURITY.md
2026-02-17 16:00:34 +01:00

4.4 KiB

MCP Read-Only Security Guide

Current Security Measures

The mssql-mcp-readonly.js file implements multiple layers of read-only enforcement:

1. Query Validation (Application Layer)

  • Only SELECT queries allowed
  • Blocks INSERT, UPDATE, DELETE, DROP, CREATE, ALTER, TRUNCATE
  • Blocks EXEC/EXECUTE (prevents stored procedure execution)
  • Blocks SP_/XP_ (prevents system stored procedures)
  • Blocks MERGE, GRANT, REVOKE, DENY
  • Prevents query chaining with semicolons

For maximum security, create a read-only database user:

-- Create a read-only user
CREATE LOGIN mcp_readonly WITH PASSWORD = 'YourSecurePassword123!';
USE Infra;
CREATE USER mcp_readonly FOR LOGIN mcp_readonly;

-- Grant only SELECT permission
GRANT SELECT ON SCHEMA::dbo TO mcp_readonly;

-- Or grant SELECT on specific tables only:
GRANT SELECT ON dbo.SDS_Teile TO mcp_readonly;
GRANT SELECT ON dbo.SDS_Teile_CA TO mcp_readonly;
GRANT SELECT ON dbo.SDS_Teile_CS TO mcp_readonly;
GRANT SELECT ON dbo.SDS_Teile_LC TO mcp_readonly;
GRANT SELECT ON dbo.SDS_Teile_ME TO mcp_readonly;
GRANT SELECT ON dbo.SDS_Teile_MK TO mcp_readonly;
GRANT SELECT ON dbo.SDS_Teile_MS TO mcp_readonly;
GRANT SELECT ON dbo.SDS_Teile_WT TO mcp_readonly;
GRANT SELECT ON dbo.SDS_Teile_EL TO mcp_readonly;

-- Explicitly deny write permissions (extra safety)
DENY INSERT, UPDATE, DELETE, ALTER ON SCHEMA::dbo TO mcp_readonly;

3. Update MCP Configuration

After creating the read-only user, update ~/.cursor/mcp.json:

{
  "mcpServers": {
    "mssql-mcp-readonly": {
      "command": "node ",
      "args": ["/home/sdsadmin/infraviewer/mssql-mcp-readonly.js"],
      "env": {
        "MSSQL_SERVER": "192.168.120.88",
        "MSSQL_PORT": "1433",
        "MSSQL_USER": "mcp_readonly",
        "MSSQL_PASSWORD": "YourSecurePassword123!",
        "MSSQL_DATABASE": "Infra",
        "MSSQL_ENCRYPT": "true",
        "MSSQL_TRUST_SERVER_CERTIFICATE": "true"
      }
    }
  }
}

Security Layers

Layer Protection Bypassed if...
Application Validation Keyword blocking Code has bugs
Database Permissions SQL Server enforced Wrong credentials used
Both Combined Double protection Nearly impossible

Testing Read-Only Access

Test 1: Valid SELECT (should work)

SELECT TOP 10 * FROM SDS_Teile

Test 2: Invalid INSERT (should fail)

INSERT INTO SDS_Teile (Teil) VALUES ('TEST')

Expected: Error: "Forbidden keyword detected: INSERT"

Test 3: Query Chaining (should fail)

SELECT 1; DROP TABLE SDS_Teile

Expected: Error: "Multiple statements not allowed"

Test 4: Stored Procedure (should fail)

EXEC sp_helpdb

Expected: Error: "Forbidden keyword detected: EXEC"

Current Setup (Application Layer Only)

[AI] → [mssql-mcp-readonly.js] → [SQL Server]
         ↑ Validates queries          ↑ Full permissions

Risk: If validation code has a bug, data could be modified

[AI] → [mssql-mcp-readonly.js] → [SQL Server with read-only user]
         ↑ Validates queries          ↑ SELECT-only permissions

Benefit: Even if validation fails, SQL Server will block write operations

Monitoring

Check MCP server logs for blocked attempts:

# If running as systemd service
journalctl -u mcp-readonly -f

# If running manually
tail -f /var/log/mcp-readonly.log

Best Practices

  1. Use dedicated read-only database user
  2. Keep validation keywords up to date
  3. Monitor for failed query attempts
  4. Regularly audit database permissions
  5. Use strong passwords for database users
  6. Enable SQL Server audit logging
  7. Limit network access to database server
  8. Keep mssql package updated (npm update mssql)

Additional Hardening

1. Add Query Size Limits

Prevent resource exhaustion:

function validateQuery(query) {
  if (query.length > 10000) {
    throw new Error("Query too long!");
  }
  // ... rest of validation
}

2. Add Rate Limiting

Prevent abuse:

const rateLimit = require('express-rate-limit');
// Limit to 100 queries per minute

3. Add Query Logging

Track all queries:

console.log(`[${new Date().toISOString()}] Query: ${query.substring(0, 100)}...`);