Top 10 OWASP ZAP Plugins for Automated Security Testing
After years of building security pipelines for startups and enterprise teams, I've seen OWASP ZAP evolve from a basic proxy tool into a comprehensive security testing platform. The real power isn't in ZAP's core functionality—it's in the plugin ecosystem that extends its capabilities for modern application stacks.
In 2025, security teams are dealing with GraphQL APIs, WebSocket connections, containerized deployments, and complex authentication flows. The default ZAP installation barely scratches the surface of what you need for effective automated security testing.
I've tested dozens of ZAP plugins across various projects, from React SPAs to microservice architectures. Here are the 10 plugins that consistently deliver value in real-world security pipelines.
Why OWASP ZAP Plugins Matter in 2025 Security Pipelines
Modern applications aren't just HTTP forms and basic authentication anymore. We're dealing with:
- Complex API architectures: GraphQL, WebSockets, gRPC endpoints
- Container-first deployments: Docker, Kubernetes, ephemeral environments
- Advanced authentication: SAML, OAuth 2.0, JWT tokens, multi-factor flows
- CI/CD integration requirements: Automated scanning, report generation, pipeline gates
The base ZAP installation handles traditional web vulnerabilities well, but falls short on modern attack vectors. Plugins bridge this gap, adding specialized scanning capabilities and integration options that security teams actually need.
1. Active Scan Rules - Beta (Essential Vulnerability Detection)
Plugin ID: ascanrulesBeta
This plugin extends ZAP's vulnerability detection with cutting-edge rules that haven't made it into the stable release yet. In my experience, it catches 20-30% more vulnerabilities than the default active scanner.
Key Features:
- Advanced SQL injection detection patterns
- NoSQL injection rules for MongoDB, Cassandra
- Server-side template injection (SSTI) detection
- Cloud metadata service checks (AWS, Azure, GCP)
Installation:
# Via ZAP CLI
zap-cli --zap-path /opt/zaproxy open-url http://localhost:8080/zapui
zap-cli --zap-path /opt/zaproxy install-plugin ascanrulesBeta
# Via Docker
docker run -t owasp/zap2docker-stable zap-cli.py --cmd -addoninstall ascanrulesBeta
Real-world impact: On a recent e-commerce audit, this plugin identified a template injection vulnerability in the order confirmation system that the standard rules missed. The beta SSTI detection caught Jinja2 template execution in user-controlled email templates.
2. WebSockets Support (Modern App Security Testing)
Plugin ID: websocket
WebSocket connections are everywhere—real-time chat, live updates, gaming applications. Most security scanners ignore WebSocket traffic entirely, creating massive blind spots.
Setup Example:
# Python script for automated WebSocket testing
from zapv2 import ZAPv2
import websocket
import json
zap = ZAPv2(proxies={'http': 'http://127.0.0.1:8080'})
# Configure WebSocket proxy
ws_url = "ws://localhost:3000/chat"
ws = websocket.WebSocket()
ws.connect(ws_url, http_proxy_host="127.0.0.1", http_proxy_port=8080)
# Send test payloads
test_payloads = [
'{"message": "<script>alert(1)</script>"}',
'{"message": "\' OR 1=1--"}',
'{"message": "{{7*7}}"}', # SSTI test
]
for payload in test_payloads:
ws.send(payload)
result = ws.recv()
print(f"Payload: {payload}, Response: {result}")
What it catches:
- XSS in WebSocket message handling
- SQL injection in real-time queries
- Authentication bypass in socket connections
- Message tampering vulnerabilities
I've used this plugin to identify critical vulnerabilities in trading platforms where WebSocket messages controlled financial transactions without proper validation.
3. GraphQL Support (API Security for Modern Stacks)
Plugin ID: graphql
GraphQL adoption has exploded, but most security tools treat GraphQL endpoints like black boxes. This plugin understands GraphQL introspection, query structure, and common GraphQL-specific vulnerabilities.
Configuration Example:
# .zaproxy/policies/graphql-policy.policy
100000 = HIGH # GraphQL Introspection
100001 = HIGH # GraphQL Query Depth
100002 = MEDIUM # GraphQL Field Suggestions
100003 = HIGH # GraphQL Directive Overloading
Automated Testing Script:
// Node.js GraphQL security testing
const { ZapClient } = require('zaproxy');
const zap = new ZapClient({ proxy: 'http://localhost:8080' });
async function testGraphQLEndpoint(endpoint) {
// Enable GraphQL plugin
await zap.spider.scan(endpoint);
// Test introspection
const introspectionQuery = `
query IntrospectionQuery {
__schema {
types {
name
fields {
name
type {
name
}
}
}
}
}
`;
// Send through ZAP proxy
const response = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: introspectionQuery }),
// Proxy through ZAP
agent: new HttpsProxyAgent('http://localhost:8080')
});
// Run active scan
await zap.ascan.scan(endpoint);
}
Common GraphQL vulnerabilities it detects:
- Introspection exposure in production
- Query depth/complexity attacks
- Field-level authorization bypass
- Batching attack vectors
4. Authentication Helper (Session Management Testing)
Plugin ID: authhelper
Modern authentication flows are complex. Multi-step OAuth, SAML assertions, JWT refresh tokens—the default ZAP authentication often fails with these patterns.
JWT Authentication Setup:
import jwt
import time
from zapv2 import ZAPv2
zap = ZAPv2()
def setup_jwt_auth():
# Create authentication context
context_id = zap.context.new_context("JWT_App")
# Configure JWT authentication
auth_config = {
'loginUrl': 'https://api.example.com/auth/login',
'loginRequestData': 'username=test&password=test123',
'tokenLocation': 'header',
'tokenName': 'Authorization',
'tokenPrefix': 'Bearer '
}
# Set up authentication method
zap.authentication.set_authentication_method(
contextid=context_id,
authmethodname='jwtAuthentication',
authmethodconfigparams=f"loginUrl={auth_config['loginUrl']}"
)
# Configure session management
zap.sessionManagement.set_session_management_method(
contextid=context_id,
methodname='jwtSessionManagement'
)
setup_jwt_auth()
SAML Integration Example:
<!-- SAML assertion testing configuration -->
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">
test@example.com
</saml:NameID>
</saml:Subject>
<!-- ZAP will automatically test assertion tampering -->
</saml:Assertion>
This plugin has saved me countless hours on enterprise applications with complex SSO implementations. It automatically handles token refresh, session validation, and multi-step authentication flows.
5. Report Generation (Executive Dashboards & Compliance)
Plugin ID: reports
Security findings are useless if stakeholders can't understand them. This plugin generates professional reports with executive summaries, compliance mappings, and technical details.
Custom Report Template:
{
"template": "custom-security-report",
"config": {
"includeSections": [
"executiveSummary",
"riskMatrix",
"vulnerabilityDetails",
"complianceMapping"
],
"complianceFrameworks": [
"OWASP_TOP_10_2021",
"PCI_DSS_4.0",
"SOC2_TYPE2"
],
"riskLevels": {
"high": "red",
"medium": "orange",
"low": "yellow",
"informational": "blue"
}
}
}
Automated Report Generation:
#!/bin/bash
# CI/CD pipeline report generation
# Run ZAP scan
docker run -v $(pwd):/zap/wrk/:rw \
-t owasp/zap2docker-stable \
zap-baseline.py -t $TARGET_URL \
-J /zap/wrk/zap-report.json \
-r /zap/wrk/zap-report.html
# Generate executive report
zap-cli generate-report \
--template executive \
--input zap-report.json \
--output security-executive-summary.pdf \
--compliance-mapping OWASP_2021,PCI_DSS
# Upload to S3 for stakeholder access
aws s3 cp security-executive-summary.pdf \
s3://security-reports/$(date +%Y-%m-%d)/
6. Selenium Integration (Dynamic Application Testing)
Plugin ID: selenium
SPAs and dynamic applications require browser automation for effective security testing. This plugin integrates Selenium WebDriver directly into ZAP scans.
React SPA Testing Example:
from selenium import webdriver
from selenium.webdriver.common.proxy import Proxy, ProxyType
from zapv2 import ZAPv2
import time
# Configure ZAP proxy
zap = ZAPv2(proxies={'http': 'http://127.0.0.1:8080'})
# Set up Selenium with ZAP proxy
proxy = Proxy()
proxy.proxy_type = ProxyType.MANUAL
proxy.http_proxy = "127.0.0.1:8080"
proxy.ssl_proxy = "127.0.0.1:8080"
capabilities = webdriver.DesiredCapabilities.CHROME
proxy.add_to_capabilities(capabilities)
driver = webdriver.Chrome(desired_capabilities=capabilities)
def test_spa_workflow():
# Navigate through SPA workflow
driver.get("https://spa-app.example.com")
# Login flow
driver.find_element_by_id("username").send_keys("testuser")
driver.find_element_by_id("password").send_keys("password123")
driver.find_element_by_id("login-btn").click()
# Wait for SPA routing
time.sleep(2)
# Navigate through protected routes
protected_routes = [
"/dashboard",
"/profile",
"/settings",
"/admin" # Test authorization
]
for route in protected_routes:
driver.get(f"https://spa-app.example.com{route}")
time.sleep(1) # Allow AJAX requests to complete
# Run active scan on discovered endpoints
zap.ascan.scan_as_user("https://spa-app.example.com", contextid=1, userid=1)
test_spa_workflow()
driver.quit()
Advanced Configuration:
selenium:
browsers:
- chrome
- firefox
headless: true
implicit_wait: 10
page_load_timeout: 30
script_timeout: 30
custom_profiles:
- name: "mobile"
user_agent: "Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X)"
viewport: "375x812"
7. Docker Integration (Containerized Security Testing)
Plugin ID: docker
Container-native security testing is essential for modern DevOps workflows. This plugin enables ZAP to run security tests against containerized applications with proper network configuration.
Docker Compose Security Testing:
# docker-compose.security.yml
version: '3.8'
services:
app:
image: myapp:latest
ports:
- "3000:3000"
networks:
- security-net
zap:
image: owasp/zap2docker-stable
command: >
zap-baseline.py
-t http://app:3000
-J /zap/wrk/report.json
-d
volumes:
- ./security-reports:/zap/wrk
networks:
- security-net
depends_on:
- app
networks:
security-net:
driver: bridge
Kubernetes Security Testing:
# k8s-security-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: zap-security-scan
spec:
template:
spec:
containers:
- name: zap-scanner
image: owasp/zap2docker-stable
command: ["/bin/bash"]
args:
- -c
- |
# Install docker plugin
zap-cli install-plugin docker
# Scan internal services
zap-baseline.py -t http://app-service.default.svc.cluster.local:8080
# Test service mesh security
zap-baseline.py -t http://api-gateway.istio-system.svc.cluster.local
volumeMounts:
- name: reports
mountPath: /zap/wrk
volumes:
- name: reports
persistentVolumeClaim:
claimName: security-reports-pvc
restartPolicy: Never
8. REST API (CI/CD Pipeline Integration)
Plugin ID: restapi
The REST API plugin transforms ZAP into a programmable security testing platform. Essential for CI/CD integration and custom security workflows.
GitHub Actions Integration:
# .github/workflows/security-scan.yml
name: Security Scan
on:
pull_request:
branches: [main]
jobs:
security-scan:
runs-on: ubuntu-latest
services:
zap:
image: owasp/zap2docker-stable
ports:
- 8080:8080
options: >-
--health-cmd "curl -f http://localhost:8080/JSON/core/view/version"
--health-interval 30s
--health-timeout 10s
--health-retries 5
steps:
- uses: actions/checkout@v3
- name: Start Application
run: |
docker build -t test-app .
docker run -d -p 3000:3000 test-app
- name: Wait for Application
run: |
timeout 60 bash -c 'until curl -f http://localhost:3000/health; do sleep 2; done'
- name: Run ZAP Security Scan
run: |
# Install REST API plugin
curl -X GET "http://localhost:8080/JSON/autoupdate/action/installAddon/?zapapiformat=JSON&name=restapi"
# Configure scan
curl -X GET "http://localhost:8080/JSON/core/action/newSession/?zapapiformat=JSON&name=security-scan"
# Spider the application
SPIDER_ID=$(curl -s "http://localhost:8080/JSON/spider/action/scan/?zapapiformat=JSON&url=http://localhost:3000" | jq -r '.scan')
# Wait for spider to complete
while [ $(curl -s "http://localhost:8080/JSON/spider/view/status/?zapapiformat=JSON&scanId=$SPIDER_ID" | jq -r '.status') != "100" ]; do
sleep 5
done
# Run active scan
SCAN_ID=$(curl -s "http://localhost:8080/JSON/ascan/action/scan/?zapapiformat=JSON&url=http://localhost:3000" | jq -r '.scan')
# Wait for scan completion
while [ $(curl -s "http://localhost:8080/JSON/ascan/view/status/?zapapiformat=JSON&scanId=$SCAN_ID" | jq -r '.status') != "100" ]; do
sleep 10
done
# Generate report
curl -s "http://localhost:8080/JSON/core/view/jsonreport/?zapapiformat=JSON" > security-report.json
- name: Process Results
run: |
# Check for high-risk vulnerabilities
HIGH_RISK=$(cat security-report.json | jq '.site[].alerts[] | select(.riskdesc | contains("High"))' | jq -s length)
if [ $HIGH_RISK -gt 0 ]; then
echo "❌ $HIGH_RISK high-risk vulnerabilities found"
exit 1
else
echo "✅ No high-risk vulnerabilities detected"
fi
- name: Upload Security Report
uses: actions/upload-artifact@v3
with:
name: security-report
path: security-report.json
Jenkins Pipeline Integration:
pipeline {
agent any
stages {
stage('Security Scan') {
steps {
script {
// Start ZAP daemon
sh 'docker run -d --name zap -p 8080:8080 owasp/zap2docker-stable zap.sh -daemon -host 0.0.0.0 -port 8080'
// Wait for ZAP to start
sh 'timeout 60 bash -c "until curl -f http://localhost:8080; do sleep 2; done"'
// Install required plugins via REST API
def plugins = ['restapi', 'graphql', 'websocket']
plugins.each { plugin ->
sh "curl -X GET 'http://localhost:8080/JSON/autoupdate/action/installAddon/?zapapiformat=JSON&name=${plugin}'"
}
// Run comprehensive scan
def zapScan = [
spider: "curl -s 'http://localhost:8080/JSON/spider/action/scan/?zapapiformat=JSON&url=${env.TARGET_URL}'",
activeScan: "curl -s 'http://localhost:8080/JSON/ascan/action/scan/?zapapiformat=JSON&url=${env.TARGET_URL}'",
report: "curl -s 'http://localhost:8080/JSON/core/view/jsonreport/?zapapiformat=JSON' > security-report.json"
]
zapScan.each { step, command ->
sh command
}
}
}
post {
always {
// Cleanup
sh 'docker stop zap && docker rm zap'
// Archive results
archiveArtifacts artifacts: 'security-report.json'
// Parse and fail on high-risk findings
script {
def report = readJSON file: 'security-report.json'
def highRiskCount = report.site[0].alerts.count { it.riskdesc.contains('High') }
if (highRiskCount > 0) {
currentBuild.result = 'FAILURE'
error("Security scan failed: ${highRiskCount} high-risk vulnerabilities found")
}
}
}
}
}
}
}
9. SAML Support (Enterprise Authentication Testing)
Plugin ID: saml
Enterprise applications rely heavily on SAML for SSO. This plugin understands SAML assertions, signature validation, and common SAML-specific attack vectors.
SAML Configuration:
<!-- saml-test-config.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="_test_request_id"
Version="2.0"
IssueInstant="2025-03-10T10:00:00Z"
Destination="https://sso.example.com/saml/sso">
<saml:Issuer>https://app.example.com</saml:Issuer>
<!-- ZAP will test assertion tampering here -->
<samlp:NameIDPolicy
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
AllowCreate="true"/>
</samlp:AuthnRequest>
Automated SAML Testing:
from zapv2 import ZAPv2
import base64
import xml.etree.ElementTree as ET
zap = ZAPv2()
def test_saml_vulnerabilities():
# Configure SAML context
context_id = zap.context.new_context("SAML_SSO")
# Set SAML endpoints
saml_endpoints = [
"https://sso.example.com/saml/sso",
"https://sso.example.com/saml/logout",
"https://app.example.com/saml/acs"
]
for endpoint in saml_endpoints:
zap.context.include_in_context(context_id, endpoint)
# Test SAML assertion tampering
test_payloads = [
# XML signature wrapping
'<saml:Assertion>WRAPPED_CONTENT</saml:Assertion>',
# XXE injection
'<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>',
# Assertion replay
'VALID_ASSERTION_REPLAY_TEST'
]
for payload in test_payloads:
encoded_payload = base64.b64encode(payload.encode()).decode()
test_url = f"https://app.example.com/saml/acs?SAMLResponse={encoded_payload}"
zap.spider.scan_as_user(test_url, contextid=context_id)
test_saml_vulnerabilities()
Common SAML vulnerabilities detected:
- XML signature wrapping attacks
- Assertion replay vulnerabilities
- XXE injection in SAML assertions
- Weak signature validation
- Missing assertion encryption
10. Community Scripts (Custom Security Rules)
Plugin ID: communityScripts
The community scripts plugin provides access to hundreds of custom security rules contributed by the ZAP community. These scripts often detect emerging vulnerabilities before they make it into official releases.
Popular Community Scripts:
# Install and configure community scripts
import requests
from zapv2 import ZAPv2
zap = ZAPv2()
# Install community scripts plugin
zap.autoupdate.install_addon('communityScripts')
# Enable useful community scripts
useful_scripts = [
'JWT None Algorithm', # JWT algorithm confusion
'Cloud Metadata Scanner', # AWS/Azure metadata exposure
'GraphQL Introspection', # Enhanced GraphQL testing
'Subdomain Takeover', # DNS-based vulnerabilities
'CORS Misconfiguration', # Advanced CORS testing
'CSP Bypass Detection', # Content Security Policy flaws
]
for script in useful_scripts:
try:
zap.script.enable(scriptname=script)
print(f"✅ Enabled: {script}")
except Exception as e:
print(f"❌ Failed to enable {script}: {e}")
Custom Script Development:
# custom-api-key-scanner.py
# Scans for exposed API keys in responses
import re
def scan_response(msg, src):
"""Custom script to detect API key exposure"""
response_body = msg.getResponseBody().toString()
# API key patterns
patterns = {
'AWS Access Key': r'AKIA[0-9A-Z]{16}',
'AWS Secret Key': r'[0-9a-zA-Z/+]{40}',
'Google API Key': r'AIza[0-9A-Za-z-_]{35}',
'Stripe Key': r'sk_live_[0-9a-zA-Z]{24}',
'GitHub Token': r'ghp_[0-9a-zA-Z]{36}',
'Slack Token': r'xox[baprs]-[0-9a-zA-Z-]{10,48}',
}
findings = []
for key_type, pattern in patterns.items():
matches = re.findall(pattern, response_body)
for match in matches:
finding = {
'type': key_type,
'key': match[:8] + '...', # Truncate for safety
'confidence': 'High',
'risk': 'High'
}
findings.append(finding)
return findings
# Register the script with ZAP
def register():
return {
'name': 'API Key Exposure Scanner',
'description': 'Detects exposed API keys in HTTP responses',
'author': 'Security Team',
'type': 'passive'
}
Setting Up ZAP Plugins in Your CI/CD Pipeline
Here's a complete CI/CD pipeline configuration that incorporates multiple ZAP plugins for comprehensive security testing:
# .gitlab-ci.yml
stages:
- build
- test
- security
- deploy
variables:
ZAP_VERSION: "2.14.0"
TARGET_URL: "https://staging.example.com"
security-scan:
stage: security
image: owasp/zap2docker-stable:${ZAP_VERSION}
services:
- name: owasp/zap2docker-stable:${ZAP_VERSION}
alias: zap
command: ["zap.sh", "-daemon", "-host", "0.0.0.0", "-port", "8080"]
script:
# Install required plugins
- |
plugins=(
"ascanrulesBeta"
"websocket"
"graphql"
"authhelper"
"reports"
"selenium"
"docker"
"restapi"
"saml"
"communityScripts"
)
for plugin in "${plugins[@]}"; do
echo "Installing plugin: $plugin"
curl -X GET "http://zap:8080/JSON/autoupdate/action/installAddon/?zapapiformat=JSON&name=$plugin"
sleep 2
done
# Configure authentication
- |
# Create security context
CONTEXT_ID=$(curl -s "http://zap:8080/JSON/context/action/newContext/?zapapiformat=JSON&contextName=SecurityTest" | jq -r '.contextId')
# Include target in context
curl -X GET "http://zap:8080/JSON/context/action/includeInContext/?zapapiformat=JSON&contextName=SecurityTest®ex=${TARGET_URL}.*"
# Set up authentication if needed
if [ ! -z "$AUTH_TOKEN" ]; then
curl -X GET "http://zap:8080/JSON/authentication/action/setAuthenticationMethod/?zapapiformat=JSON&contextId=$CONTEXT_ID&authMethodName=httpAuthentication"
fi
# Run comprehensive scan
- |
# Spider scan
echo "Starting spider scan..."
SPIDER_ID=$(curl -s "http://zap:8080/JSON/spider/action/scan/?zapapiformat=JSON&url=${TARGET_URL}&contextName=SecurityTest" | jq -r '.scan')
# Wait for spider completion
while [ $(curl -s "http://zap:8080/JSON/spider/view/status/?zapapiformat=JSON&scanId=$SPIDER_ID" | jq -r '.status') != "100" ]; do
echo "Spider progress: $(curl -s "http://zap:8080/JSON/spider/view/status/?zapapiformat=JSON&scanId=$SPIDER_ID" | jq -r '.status')%"
sleep 10
done
# Active scan
echo "Starting active scan..."
SCAN_ID=$(curl -s "http://zap:8080/JSON/ascan/action/scan/?zapapiformat=JSON&url=${TARGET_URL}&contextId=$CONTEXT_ID" | jq -r '.scan')
# Wait for scan completion
while [ $(curl -s "http://zap:8080/JSON/ascan/view/status/?zapapiformat=JSON&scanId=$SCAN_ID" | jq -r '.status') != "100" ]; do
echo "Active scan progress: $(curl -s "http://zap:8080/JSON/ascan/view/status/?zapapiformat=JSON&scanId=$SCAN_ID" | jq -r '.status')%"
sleep 30
done
# Generate reports
- |
# JSON report for processing
curl -s "http://zap:8080/JSON/core/view/jsonreport/?zapapiformat=JSON" > security-report.json
# HTML report for human review
curl -s "http://zap:8080/OTHER/core/other/htmlreport/" > security-report.html
# XML report for compliance
curl -s "http://zap:8080/OTHER/core/other/xmlreport/" > security-report.xml
# Process results and set pipeline status
- |
# Count vulnerabilities by risk level
HIGH_RISK=$(cat security-report.json | jq '[.site[].alerts[] | select(.riskdesc | contains("High"))] | length')
MEDIUM_RISK=$(cat security-report.json | jq '[.site[].alerts[] | select(.riskdesc | contains("Medium"))] | length')
LOW_RISK=$(cat security-report.json | jq '[.site[].alerts[] | select(.riskdesc | contains("Low"))] | length')
echo "Security Scan Results:"
echo "High Risk: $HIGH_RISK"
echo "Medium Risk: $MEDIUM_RISK"
echo "Low Risk: $LOW_RISK"
# Fail pipeline on high-risk vulnerabilities
if [ $HIGH_RISK -gt 0 ]; then
echo "❌ Pipeline failed due to high-risk vulnerabilities"
exit 1
fi
# Warn on medium-risk vulnerabilities
if [ $MEDIUM_RISK -gt 5 ]; then
echo "⚠️ Warning: High number of medium-risk vulnerabilities detected"
fi
echo "✅ Security scan completed successfully"
artifacts:
when: always
reports:
junit: security-report.xml
paths:
- security-report.json
- security-report.html
- security-report.xml
expire_in: 30 days
only:
- merge_requests
- main
Performance Benchmarks: Plugin Impact on Scan Times
I've benchmarked plugin performance across different application types. Here's what you can expect:
| Plugin | Baseline Impact | Large App Impact | Memory