Security testing used to be something I bolted on at the very end of a release cycle, usually a week before launch when there was barely any time left to fix what got found. That approach doesn’t scale, and it definitely doesn’t fit into a modern CI/CD workflow. Integrating a DAST (Dynamic Application Security Testing) tool like Acunetix directly into Jenkins was one of the changes that made security testing feel like a natural part of the pipeline instead of a last-minute scramble.
In this guide, I’ll walk through setting up Jenkins to trigger Acunetix scans automatically, parse results, and gate deployments based on vulnerability findings.
Why Automate Security Scanning in CI/CD
Acunetix is a web vulnerability scanner that detects issues like SQL injection, cross-site scripting (XSS), misconfigurations, and outdated software components by actively crawling and attacking a running web application (hence “dynamic” testing, as opposed to static code analysis). Running this manually before every release is slow and inconsistent. Automating it inside Jenkins means:
- Every build against a staging environment gets scanned automatically.
- Vulnerabilities are caught before reaching production, not after.
- Security becomes a repeatable, auditable part of the release process (helpful for compliance frameworks like PCI-DSS, SOC 2, or ISO 27001).
Jenkins Architecture Context
Acunetix scans typically target a live, deployed instance of your application, meaning this stage in the pipeline usually happens after a deployment to a staging or QA environment. Jenkins triggers the scan via the Acunetix REST API, waits for results, and then processes the report — either as a manual gate or an automated pass/fail decision based on vulnerability severity thresholds.
Prerequisites
- A running Acunetix instance (on-premise or Acunetix 360/Cloud) with API access enabled.
- An Acunetix API key, generated from your Acunetix account settings.
- A deployed, reachable target application (staging URL) for Acunetix to scan.
- Jenkins with the HTTP Request Plugin installed (used to call the Acunetix REST API).
Step 1: Install Required Jenkins Plugins
From Manage Jenkins > Plugins, install:
- HTTP Request Plugin — for calling Acunetix’s REST API.
- Pipeline Utility Steps — for parsing JSON responses.
- Credentials Binding Plugin — to securely store your Acunetix API key.
Step 2: Store the Acunetix API Key as a Jenkins Credential
Go to Manage Jenkins > Credentials > System > Global Credentials, and add a new Secret text credential with the ID acunetix-api-key, pasting in your Acunetix API token.
Step 3: Create a Target in Acunetix (One-Time Setup)
Before scanning via API, Acunetix needs a registered “Target” (the URL to scan). You can create this manually in the Acunetix UI, or via API:
curl -s -k -X POST "https://<acunetix-host>:3443/api/v1/targets" \
-H "X-Auth: $ACUNETIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"address": "https://staging.myapp.com",
"description": "Staging environment"
}'
This returns a target_id you’ll use to trigger scans.
Step 4: Jenkinsfile Pipeline for Acunetix Scanning
pipeline {
agent any
environment {
ACUNETIX_HOST = 'https://acunetix.internal:3443'
TARGET_ID = 'your-target-id-here'
}
stages {
stage('Deploy to Staging') {
steps {
sh './deploy.sh staging'
}
}
stage('Trigger Acunetix Scan') {
steps {
withCredentials([string(credentialsId: 'acunetix-api-key', variable: 'ACUNETIX_API_KEY')]) {
script {
def response = httpRequest(
url: "${ACUNETIX_HOST}/api/v1/scans",
httpMode: 'POST',
customHeaders: [
[name: 'X-Auth', value: ACUNETIX_API_KEY],
[name: ‘Content-Type’, value: ‘application/json’]
], requestBody: “””{ “target_id”: “${TARGET_ID}”, “profile_id”: “11111111-1111-1111-1111-111111111111”, “schedule”: { “disable”: false, “start_date”: null, “time_sensitive”: false } }””” ) echo “Scan triggered: ${response.content}” } } } } stage(‘Poll for Scan Completion’) { steps { withCredentials([string(credentialsId: ‘acunetix-api-key’, variable: ‘ACUNETIX_API_KEY’)]) { script { def status = ‘processing’ timeout(time: 60, unit: ‘MINUTES’) { while (status != ‘completed’) { sleep(60) def check = httpRequest( url: “${ACUNETIX_HOST}/api/v1/scans”, customHeaders: [[name: ‘X-Auth’, value: ACUNETIX_API_KEY]] ) def json = readJSON text: check.content status = json.scans[0].current_session.status echo “Current scan status: ${status}” } } } } } } stage(‘Evaluate Vulnerabilities’) { steps { withCredentials([string(credentialsId: ‘acunetix-api-key’, variable: ‘ACUNETIX_API_KEY’)]) { script { def vulnResponse = httpRequest( url: “${ACUNETIX_HOST}/api/v1/vulnerabilities?q=severity:>=3”, customHeaders: [[name: ‘X-Auth’, value: ACUNETIX_API_KEY]] ) def vulns = readJSON text: vulnResponse.content if (vulns.vulnerabilities.size() > 0) { error “Found ${vulns.vulnerabilities.size()} high/critical vulnerabilities. Failing build.” } else { echo “No high/critical vulnerabilities found.” } } } } } } post { always { echo “Scan report available at: ${ACUNETIX_HOST}/#/scans” } failure { mail to: ‘security-team@example.com’, subject: “Security Scan Failed: ${env.JOB_NAME}”, body: “Vulnerabilities found. Check Acunetix dashboard: ${ACUNETIX_HOST}” } } }
Understanding Severity Gating
Acunetix reports vulnerabilities on a severity scale (0 = informational, up to 4 = critical). The query severity:>=3 in the example above filters for high and critical issues only. I recommend starting your gating threshold conservative (only block on critical) and tightening it over time as your team fixes the backlog of known medium-severity issues — otherwise you risk blocking every single deployment on day one and frustrating the whole team.
Integrating with Git and GitHub
Tie scan results back to your pull requests using GitHub status checks so reviewers see security status directly:
post {
failure {
githubNotify status: 'FAILURE', context: 'acunetix-scan', description: 'Vulnerabilities detected'
}
success {
githubNotify status: 'SUCCESS', context: 'acunetix-scan', description: 'No critical vulnerabilities'
}
}
Integrating with Docker and Kubernetes
If your staging environment runs in Kubernetes, trigger the Acunetix scan only after your Kubernetes rollout is confirmed healthy:
stage('Wait for Rollout') {
steps {
sh 'kubectl rollout status deployment/myapp-staging --timeout=120s'
}
}
This ensures Acunetix isn’t scanning a half-deployed or crashing application, which would produce noisy, unreliable results.
Monitoring and Reporting
Beyond pass/fail gating, export scan reports as Jenkins build artifacts for historical tracking:
stage('Archive Report') {
steps {
sh "curl -k -H 'X-Auth: ${ACUNETIX_API_KEY}' ${ACUNETIX_HOST}/api/v1/scans/export -o acunetix-report.json"
archiveArtifacts artifacts: 'acunetix-report.json'
}
}
This gives your security team an audit trail across builds, which is often required for compliance reviews.
Troubleshooting Common Issues
- SSL certificate errors connecting to Acunetix — common with self-signed certs; use
-kin curl calls or properly install the CA cert on Jenkins agents (avoid disabling SSL verification in production). - Scan takes too long and pipeline times out — increase the
timeoutblock duration, or use scan profiles tuned for CI (lighter, faster scan profiles rather than a full deep scan). - False positives blocking every build — work with your security team to add exceptions/false-positive suppressions in Acunetix directly rather than loosening your Jenkins threshold.
Best Practices
- Run full deep scans on a schedule (nightly/weekly), and lighter/faster scans on every pipeline run.
- Never scan production directly from an automated pipeline without safeguards — target staging or a dedicated security testing environment.
- Store scan reports as build artifacts for compliance and historical trend analysis.
- Gate merges/deploys only on high and critical severity findings initially.
- Rotate and secure your Acunetix API key using Jenkins Credentials, never hardcoded in the Jenkinsfile.
FAQs
Can Acunetix scan APIs, not just web UIs? Yes, Acunetix supports scanning REST APIs when given an OpenAPI/Swagger spec or Postman collection as the scan target definition.
Does Acunetix integration require Acunetix Enterprise? The REST API is available in Acunetix 360, Online, and Enterprise/Premium tiers; older on-premise standard licenses may have more limited API access — check your license tier.
How long does a typical scan take in a CI/CD pipeline? It depends heavily on application size and scan profile, but a “quick scan” profile is often used in CI, taking anywhere from 10–40 minutes versus hours for a full deep scan.
Should I run Acunetix on every commit? Not typically — running it on every merge to a staging branch or on a schedule is more practical given scan duration; reserve full scans for nightly builds or pre-release gates.
Summary
Integrating Acunetix into Jenkins turns security testing from a manual, end-of-cycle task into an automated, repeatable part of your CI/CD pipeline. By triggering scans via the Acunetix REST API, polling for completion, and gating deployments on severity thresholds, you catch vulnerabilities earlier — when they’re cheaper and easier to fix — while building an auditable security history for every release.
References
- Acunetix API Documentation: https://www.acunetix.com/support/docs/api/
- Jenkins HTTP Request Plugin: https://plugins.jenkins.io/http_request/
- Jenkins Pipeline Utility Steps Plugin: https://plugins.jenkins.io/pipeline-utility-steps/
- Jenkins Credentials Plugin: https://plugins.jenkins.io/credentials/
