Setting up vulnerability scanner for website
Automated vulnerability scanner checks the application for known CVEs, misconfigurations, and OWASP Top 10 vulnerabilities. Runs regularly in CI/CD pipeline or on schedule, ensuring continuous security monitoring.
Tools
DAST (dynamic scanning against running application):
- OWASP ZAP — open, full-featured, CI/CD integration
- Nuclei — fast, template-based, 7000+ checks
- Nikto — specializes in web server configuration
SAST (static scanning by code):
- Semgrep — multilingual, OWASP rules
- SonarQube — complete static analysis with dashboard
SCA (dependencies):
-
npm audit,composer audit,pip-audit - Trivy — containers + dependencies
- Snyk — commercial, deep GitHub integration
OWASP ZAP in CI/CD (GitHub Actions)
name: Security Scan
on:
schedule:
- cron: '0 3 * * 1'
push:
branches: [main]
jobs:
zap-scan:
runs-on: ubuntu-latest
steps:
- name: ZAP Baseline Scan
uses: zaproxy/[email protected]
with:
target: 'https://staging.example.com'
rules_file_name: '.zap/rules.tsv'
cmd_options: '-a -j'
- name: Upload Report
uses: actions/upload-artifact@v3
with:
name: zap-report
path: report_html.html
Nuclei — template scanning
go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
nuclei -update-templates
nuclei -u https://target.example.com \
-t cves/ \
-t misconfigurations/ \
-t exposures/ \
-severity critical,high \
-o nuclei_report.json \
-json
Semgrep SAST in CI/CD
- name: Semgrep SAST
uses: semgrep/semgrep-action@v1
with:
config: >-
p/owasp-top-ten
p/php
p/laravel
p/javascript
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
Dependency Scanning
composer audit
npm audit --audit-level=high
npx audit-ci --high
pip-audit --output=json -o pip-audit.json
trivy image myapp:latest \
--severity HIGH,CRITICAL \
--format json \
-o trivy-report.json
SonarQube — continuous SAST
services:
sonarqube:
image: sonarqube:community
ports:
- "9000:9000"
environment:
SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
volumes:
- sonar_data:/opt/sonarqube/data
sonar.projectKey=my-webapp
sonar.sources=app,resources/js
sonar.exclusions=**/vendor/**,**/node_modules/**
sonar.php.coverage.reportPaths=coverage.xml
Schedule and notifications
security-scan:
stage: security
image: owasp/zap2docker-stable
script:
- zap-baseline.py -t $STAGING_URL -r zap-report.html
artifacts:
paths: [zap-report.html]
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
only:
- schedules
Notifications in Slack/Telegram on Critical/High discovery:
CRITICAL=$(cat nuclei_report.json | jq '[.[] | select(.info.severity == "critical")] | length')
if [ "$CRITICAL" -gt "0" ]; then
curl -X POST $SLACK_WEBHOOK \
-H 'Content-type: application/json' \
--data "{\"text\":\"Found ${CRITICAL} critical vulnerabilities\"}"
fi
Managing results (False Positives)
# .zap/rules.tsv
10016 IGNORE
10021 IGNORE
90033 IGNORE
Implementation Timeline
- OWASP ZAP baseline in GitHub Actions: 1 day
- Nuclei + notifications: 1 day
- Semgrep SAST + Dependency scanning: 1–2 days
- SonarQube full setup: 2–3 days







