Automated SAST And DAST Security Testing For MCP Gateway
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.