Automated SAST And DAST Security Testing For MCP Gateway

by StackCamp Team 57 views

In the realm of modern software development, security is not merely an afterthought but an integral component of the development lifecycle. For the MCP Gateway, a robust and comprehensive security testing strategy is paramount. This article delves into the implementation of automated security testing using a combination of Static Application Security Testing (SAST) with Semgrep and Dynamic Application Security Testing (DAST) with OWASP ZAP. This dual approach ensures that every line of code and running endpoint is fortified against common vulnerabilities, injection attacks, authentication bypasses, and configuration weaknesses. By integrating both SAST and DAST, we achieve a holistic security coverage that identifies vulnerabilities at both the code level and runtime, crucial for a gateway handling authentication, JSON-RPC requests, and sensitive configuration data.

Understanding SAST and DAST: A Comparative Analysis

To fully appreciate the power of our security testing automation, it's essential to understand the difference between SAST and DAST. These two methodologies offer distinct but complementary approaches to identifying vulnerabilities.

Static Application Security Testing (SAST): Code-Level Vigilance

Static Application Security Testing (SAST) is akin to a meticulous code review performed by a security expert. It analyzes the source code and configuration files before the application is ever run. The primary goal of SAST is to catch insecure patterns early and inexpensively. For example, it can identify potential SQL injection vulnerabilities arising from string-building SQL queries. Our tool of choice for SAST is Semgrep, a powerful static analysis tool that excels at identifying a wide range of security issues, from hardcoded passwords to cross-site scripting (XSS) vulnerabilities. Semgrep's strength lies in its ability to scan code for patterns indicative of security flaws, ensuring that potential vulnerabilities are flagged before they can be exploited in a live environment.

Dynamic Application Security Testing (DAST): Runtime Resilience

Dynamic Application Security Testing (DAST), on the other hand, takes a runtime approach. It analyzes a live instance of the application by sending it malicious requests and observing its responses. The primary goal of DAST is to provoke the server and check its responses and headers for signs of vulnerabilities. OWASP ZAP (Zed Attack Proxy) is our chosen DAST tool, renowned for its ability to identify a wide array of runtime vulnerabilities, including authentication bypasses and injection attacks. OWASP ZAP's dynamic analysis complements SAST by uncovering vulnerabilities that are only apparent when the application is running, such as those related to server configuration or runtime behavior.

SAST vs. DAST: A Head-to-Head Comparison

Phase What it analyzes Primary goal Tool to use
SAST (before the code ever runs) Source code & config files Catch insecure patterns (e.g. string-building SQL) early and cheaply Semgrep
DAST (while the app is running) A live instance of your API/site Provoke the server with evil requests & check responses/headers OWASP ZAP

MCP Gateway Security Testing Architecture

Our security testing architecture for the MCP Gateway is designed to be comprehensive and multi-layered, encompassing static analysis, dynamic analysis, dependency scanning, and configuration auditing. This layered approach ensures that we cover a wide range of potential vulnerabilities, from code-level flaws to runtime issues and misconfigurations.

A Visual Overview: The Security Testing Suite

graph TD
    A[Security Testing Suite] --> B[Static Analysis - SAST]
    A --> C[Dynamic Analysis - DAST]
    A --> D[Dependency Scanning]
    A --> E[Configuration Auditing]
    
    B --> B1[Semgrep - Code Patterns]
    B --> B2[SQL Injection Detection]
    B --> B3[XSS Prevention Check]
    B --> B4[Hard-coded Secrets]
    B --> B5[Authentication Bypasses]
    
    C --> C1[OWASP ZAP - Runtime]
    C --> C2[API Endpoint Fuzzing]
    C --> C3[Authentication Testing]
    C --> C4[Header Security Checks]
    C --> C5[Input Validation Testing]
    
    D --> D1[pip-audit - Known CVEs]
    D --> D2[Safety - PyPI Vulnerabilities]
    D --> D3[Outdated Dependencies]
    
    E --> E1[TLS Configuration]
    E --> E2[Environment Variables]
    E --> E3[Default Credentials]
    E --> E4[Secure Headers]

This diagram illustrates how our security testing suite integrates various components to provide a holistic view of the MCP Gateway's security posture. Each component plays a critical role in identifying and mitigating potential vulnerabilities.

SAST with Semgrep: Identifying Code-Level Vulnerabilities

Semgrep is a cornerstone of our SAST strategy, enabling us to identify a wide range of code-level vulnerabilities. Its ability to scan code for specific patterns makes it an invaluable tool for detecting common security flaws.

Semgrep Rules: Defining Security Patterns

Semgrep operates using rules, which define patterns indicative of security vulnerabilities. These rules can be customized to target specific issues relevant to the MCP Gateway. For example, we have rules to detect hardcoded passwords, potential SQL injection vulnerabilities, and insecure random number generation. Below are examples of Semgrep rules used in our security testing suite. These rules illustrate the types of security patterns we actively scan for in our codebase.

# security/semgrep-rules.yml
rules:
- id: hardcoded-password
  patterns:
  - pattern: password = "$PASSWORD"
  - pattern: PASSWORD = "$PASSWORD"
  - metavariable-regex:
      metavariable: $PASSWORD
      regex: ^.{8,}$
  message: "Hard-coded password detected"
  languages: [python]
  severity: ERROR

- id: sql-injection-risk
  patterns:
  - pattern: $QUERY = f"SELECT ... {$USER_INPUT}"
  - pattern: $QUERY = "SELECT ... " + $USER_INPUT
  - pattern: cursor.execute($QUERY % $USER_INPUT)
  message: "Potential SQL injection vulnerability"
  languages: [python]
  severity: ERROR

- id: jwt-hardcoded-secret
  patterns:
  - pattern: jwt.encode($PAYLOAD, "$SECRET", ...)
  - metavariable-regex:
      metavariable: $SECRET
      regex: ^[a-zA-Z0-9]{8,}$
  message: "Hard-coded JWT secret key"
  languages: [python]
  severity: ERROR

- id: insecure-random
  patterns:
  - pattern: random.random()
  - pattern: random.randint(...)
  message: "Use secrets module for cryptographic randomness"
  languages: [python]
  severity: WARNING

- id: debug-mode-enabled
  patterns:
  - pattern: debug=True
  - pattern: DEBUG = True
  message: "Debug mode should not be enabled in production"
  languages: [python]
  severity: WARNING

Custom Semgrep Rules for MCP Gateway: Tailored Security

In addition to general security rules, we've developed custom Semgrep rules specifically tailored to the MCP Gateway's architecture and functionality. These rules target potential vulnerabilities unique to our application, such as authentication bypasses and insecure JSONPath usage. These custom rules enhance our security testing automation, ensuring comprehensive coverage of the MCP Gateway's specific security needs.

# security/mcp-gateway-rules.yml
rules:
- id: mcp-auth-bypass
  patterns:
  - pattern: app.dependency_overrides[$AUTH_FUNC] = lambda: $USER
  message: "Authentication bypass detected - ensure this is test-only"
  languages: [python]
  severity: WARNING

- id: mcp-unsafe-jsonpath
  patterns:
  - pattern: jsonpath_ng.parse($USER_INPUT)
  - pattern: jq.compile($USER_INPUT)
  message: "JSONPath/JQ expressions from user input may be unsafe"
  languages: [python]
  severity: WARNING

- id: mcp-insecure-transport
  patterns:
  - pattern: skip_ssl_verify=True
  - pattern: verify=False
  message: "SSL verification disabled - security risk"
  languages: [python]
  severity: ERROR

- id: mcp-weak-auth
  patterns:
  - pattern: basic_auth_password = \"changeme\"
  - pattern: jwt_secret_key = \"my-test-key\"
  message: "Default/weak authentication credentials"
  languages: [python]
  severity: ERROR

DAST with OWASP ZAP: Runtime Vulnerability Detection

OWASP ZAP is our DAST tool of choice, enabling us to identify runtime vulnerabilities by actively probing the application. Its comprehensive scanning capabilities and customizable configuration options make it an ideal tool for securing the MCP Gateway.

OWASP ZAP Configuration: Tailoring the Scan

To ensure effective dynamic analysis, we configure OWASP ZAP with specific settings relevant to the MCP Gateway. This includes setting the spidering depth, scan policy, authentication method, and rules for identifying vulnerabilities. Our ZAP configuration ensures that the dynamic analysis is tailored to the MCP Gateway's specific characteristics, maximizing the effectiveness of our security testing automation.

# security/zap-config.yml
zap:
  spider:
    maxDuration: 5  # minutes
    maxDepth: 5
    maxChildren: 10
  
  activeScan:
    policy: "Default Policy"
    maxRuleDurationInMins: 5
    maxScanDurationInMins: 15
  
  authentication:
    method: "httpAuthentication"
    httpAuthentication:
      hostname: "localhost"
      port: 4444
      realm: ""
      username: "admin"
      password: "changeme"
  
  globalExcludeUrl:
    - ".*logout.*"
    - ".*\\.css"
    - ".*\\.js"
    - ".*\\.png"
    - ".*\\.jpg"
  
  rules:
    - id: 10035  # Strict-Transport-Security missing
      action: "FAIL"
    - id: 10036  # Server header information leak
      action: "WARN"
    - id: 40012  # Cross-Site Scripting (Reflected)
      action: "FAIL"
    - id: 40014  # Cross-Site Scripting (Persistent)
      action: "FAIL"
    - id: 40018  # SQL Injection
      action: "FAIL"
    - id: 40019  # SQL Injection (MySQL)
      action: "FAIL"

ZAP Custom Scripts for MCP Gateway: Targeted Testing

To further enhance our DAST capabilities, we utilize custom ZAP scripts that target specific aspects of the MCP Gateway's functionality. For example, we have scripts to test authentication bypass attempts and JSON-RPC endpoint security. These scripts allow us to perform targeted testing, ensuring that critical areas of the application are thoroughly vetted for vulnerabilities. Our custom scripts demonstrate the flexibility of OWASP ZAP and its ability to be tailored to the unique security needs of the MCP Gateway.

# security/zap-scripts/mcp-auth-test.py
"""Custom ZAP script for testing MCP Gateway authentication."""

def scanNode(sas, msg):
    """Test authentication bypass attempts."""
    # Test endpoints without auth headers
    endpoints = [
        "/admin/tools",
        "/admin/servers", 
        "/admin/resources",
        "/rpc",
        "/metrics"
    ]
    
    for endpoint in endpoints:
        # Test without Authorization header
        test_msg = msg.cloneRequest()
        test_msg.getRequestHeader().setURI(endpoint)
        test_msg.getRequestHeader().setHeader("Authorization", None)
        
        sas.sendAndReceive(test_msg)
        
        if test_msg.getResponseHeader().getStatusCode() == 200:
            sas.raiseAlert(
                risk=3,  # High
                confidence=3,  # High
                name="Authentication Bypass",
                description=f"Endpoint {endpoint} accessible without authentication",
                uri=endpoint,
                param="",
                attack="No Authorization header",
                otherInfo="",
                solution="Ensure all sensitive endpoints require authentication",
                reference="",
                evidence="",
                cweId=287,  # CWE-287: Improper Authentication
                wascId=1,   # WASC-1: Insufficient Authentication
                msg=test_msg
            )

Streamlining Security Testing with Make Targets

To simplify the execution of our security testing suite, we've integrated various security checks into our Makefile. This allows developers to easily run comprehensive security tests with a single command, ensuring that security is a seamless part of the development process. Our Make targets abstract the complexity of running individual security tools, making it easy for developers to incorporate security testing into their workflow.

Available Make Targets: A Security Testing Arsenal

Target Purpose
make security-all Run complete security testing suite (SAST + DAST + deps)
make security-sast Static Application Security Testing with Semgrep
make security-dast Dynamic Application Security Testing with OWASP ZAP
make security-deps Dependency vulnerability scanning
make security-install Install all security testing dependencies
make security-report Generate comprehensive security testing report
make security-baseline Quick security baseline scan for CI/PR validation
make security-full Extended security testing for nightly runs
make security-clean Clean security testing artifacts and reports
make security-config Validate security configuration and settings
make security-headers Test HTTP security headers configuration
make security-auth Test authentication and authorization mechanisms

Bold targets are mandatory; CI must fail if critical or high-severity security issues are discovered.

Example Makefile Integration: Security at Your Fingertips

.PHONY: security-all security-sast security-dast security-deps \
           security-install security-report security-baseline security-clean

# Install all security testing dependencies
security-install:
	@echo "๐Ÿ”ง  Installing security testing dependencies..."
	pip install -r requirements-security.txt
	@echo "โœ…  Security tools installed"

# Run complete security testing suite
security-all: security-sast security-dast security-deps
	@echo "๐Ÿ›ก๏ธ  Complete security testing suite finished"
	make security-report

# Static Application Security Testing
security-sast:
	@echo "๐Ÿ”  Running Semgrep SAST analysis..."
	@mkdir -p reports/security
	semgrep scan \
		--config=security/semgrep-rules.yml \
		--config=security/mcp-gateway-rules.yml \
		--config=p/security-audit \
		--config=p/secrets \
		--config=p/sql-injection \
		--config=p/xss \
		--sarif \
		--output=reports/security/semgrep.sarif \
		--error \
		.
	@echo "๐Ÿ“Š  Running Bandit security linter..."
	bandit -r mcpgateway/ -f json -o reports/security/bandit.json || true

# Dynamic Application Security Testing
security-dast:
	@echo "๐ŸŒ  Running OWASP ZAP DAST analysis..."
	@mkdir -p reports/security
	@echo "Starting test server..."
	make run-dev &
	sleep 15
	# Baseline scan (passive)
	docker run --rm -v $(PWD)/reports/security:/zap/wrk/ \
		--network host \
		ghcr.io/zaproxy/zaproxy:stable \
		zap-baseline.py \
		-t http://localhost:4444 \
		-J zap-baseline.json \
		-r zap-baseline.html \
		-m 5 -T 300 \
		-z "-configfile /zap/wrk/zap-config.yml"
	# Full active scan
	docker run --rm -v $(PWD)/reports/security:/zap/wrk/ \
		--network host \
		ghcr.io/zaproxy/zaproxy:stable \
		zap-full-scan.py \
		-t http://localhost:4444 \
		-J zap-full.json \
		-r zap-full.html \
		-m 10 -T 600 \
		-z "-configfile /zap/wrk/zap-config.yml"
	pkill -f "make run-dev" || true

# Dependency vulnerability scanning
security-deps:
	@echo "๐Ÿ“ฆ  Scanning dependencies for vulnerabilities..."
	@mkdir -p reports/security
	pip-audit --format=json --output=reports/security/pip-audit.json
	safety check --json --output reports/security/safety.json || true

# Quick security baseline for CI
security-baseline:
	@echo "โšก  Running quick security baseline..."
	semgrep scan \
		--config=p/security-audit \
		--config=p/secrets \
		--error \
		--quiet \
		.
	pip-audit --format=cyclonedx --output=/dev/null

# Generate security report
security-report:
	@echo "๐Ÿ“Š  Generating security testing report..."
	python scripts/generate_security_report.py

# Clean security artifacts
security-clean:
	@echo "๐Ÿงน  Cleaning security testing artifacts..."
	rm -rf reports/security/
	rm -f zap-*.json zap-*.html

CI/CD Integration: Automating Security Checks

To ensure that security testing is consistently performed, we've integrated our security checks into our CI/CD pipeline using GitHub Actions. This automation ensures that every code change is subjected to security analysis, and vulnerabilities are identified early in the development lifecycle. Our CI/CD integration provides continuous security monitoring, preventing vulnerabilities from reaching production.

GitHub Actions Workflow: Security as a First-Class Citizen

# .github/workflows/security-testing.yml
name: Security Testing

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 3 * * *'  # Nightly at 3 AM

jobs:
  security-baseline:
    name: Security Baseline (PR)
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request'
    
    steps:
      - name: โฌ‡๏ธ Checkout source
        uses: actions/checkout@v4
      
      - name: ๐Ÿ Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"
          cache: pip
      
      - name: ๐Ÿ“ฆ Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -e .[dev]
          make security-install
      
      - name: โšก Run security baseline
        run: make security-baseline
        timeout-minutes: 10
      
      - name: ๐Ÿ“Š Upload baseline results
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: security-baseline-results
          path: reports/security/

  security-sast:
    name: Static Security Analysis (SAST)
    runs-on: ubuntu-latest
    
    steps:
      - name: โฌ‡๏ธ Checkout source
        uses: actions/checkout@v4
      
      - name: ๐Ÿ Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"
          cache: pip
      
      - name: ๐Ÿ“ฆ Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -e .[dev]
          make security-install
      
      - name: ๐Ÿ” Run SAST analysis
        run: make security-sast
        timeout-minutes: 15
      
      - name: ๐Ÿ“Š Upload SAST results to GitHub Security
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: reports/security/semgrep.sarif
          category: semgrep
      
      - name: ๐Ÿ“‹ Upload SAST artifacts
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: sast-results
          path: reports/security/

  security-dast:
    name: Dynamic Security Analysis (DAST)
    runs-on: ubuntu-latest
    if: github.event_name == 'schedule' || github.event_name == 'push'
    
    steps:
      - name: โฌ‡๏ธ Checkout source
        uses: actions/checkout@v4
      
      - name: ๐Ÿ Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"
          cache: pip
      
      - name: ๐Ÿ“ฆ Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -e .[dev]
      
      - name: ๐ŸŒ Run DAST analysis
        run: make security-dast
        timeout-minutes: 30
      
      - name: ๐Ÿ“‹ Upload DAST artifacts
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: dast-results
          path: |
            reports/security/
            zap-*.json
            zap-*.html

  security-dependencies:
    name: Dependency Security Scan
    runs-on: ubuntu-latest
    
    steps:
      - name: โฌ‡๏ธ Checkout source
        uses: actions/checkout@v4
      
      - name: ๐Ÿ Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"
          cache: pip
      
      - name: ๐Ÿ“ฆ Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -e .[dev]
          make security-install
      
      - name: ๐Ÿ“ฆ Run dependency scan
        run: make security-deps
        timeout-minutes: 10
      
      - name: ๐Ÿ“‹ Upload dependency results
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: dependency-scan-results
          path: reports/security/

  security-report:
    name: Generate Security Report
    runs-on: ubuntu-latest
    needs: [security-sast, security-dast, security-dependencies]
    if: always() && (github.event_name == 'schedule' || github.event_name == 'push')
    
    steps:
      - name: โฌ‡๏ธ Checkout source
        uses: actions/checkout@v4
      
      - name: ๐Ÿ Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      
      - name: ๐Ÿ“ฅ Download all security artifacts
        uses: actions/download-artifact@v4
        with:
          path: artifacts/
      
      - name: ๐Ÿ“ Organize security results
        run: |
          mkdir -p reports/security
          find artifacts/ -name "*.json" -o -name "*.sarif" -o -name "*.html" | \
            xargs -I {} cp {} reports/security/
      
      - name: ๐Ÿ“Š Generate comprehensive report
        run: |
          pip install -r requirements-security.txt
          python scripts/generate_security_report.py
      
      - name: ๐Ÿšจ Check for critical findings
        run: |
          python -c "
          import json
          with open('reports/security/security-report.json') as f:
              report = json.load(f)
          
          critical_findings = [f for f in report.get('all_findings', []) 
                             if f.get('severity') in ['error', 'HIGH', 'High']]
          
          if critical_findings:
              print(f'๐Ÿšจ Found {len(critical_findings)} critical findings!')
              for finding in critical_findings[:5]:  # Show first 5
                  print(f'  - {finding.get(\"message\", \"Unknown\")} in {finding.get(\"file\", \"unknown\")}')
              exit(1)
          else:
              print('โœ… No critical security findings detected')
          "
      
      - name: ๐Ÿ“‹ Upload final security report
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: comprehensive-security-report
          path: reports/security/security-report.*      

Conclusion

By implementing comprehensive SAST and DAST security testing with Semgrep and OWASP ZAP, integrated into our CI/CD pipeline and accessible through simple Make targets, we ensure that the MCP Gateway is fortified against a wide range of potential vulnerabilities. This proactive approach to security not only protects our application but also fosters a culture of security within our development team. The combination of static and dynamic analysis provides a holistic view of the application's security posture, enabling us to identify and address vulnerabilities before they can be exploited. Our commitment to security testing automation reflects our dedication to building secure and resilient software.