QA How-To
Burp Suite API DAST CI Tutorial (2026)
Follow this Burp Suite API DAST CI tutorial to scope an OpenAPI scan, add bearer authentication, gate GitHub Actions, and publish JUnit evidence for APIs.
22 min read | 2,873 words
TL;DR
Provide Burp Suite DAST with a scoped OpenAPI definition, authentication secret, and CI configuration, then run its official Docker scan container. Gate on medium-or-higher issues with firm-or-higher confidence, and always retain the generated JUnit report.
Key Takeaways
- Run the official Burp Suite DAST scan container from a CI agent that can reach both the DAST server and the staging API.
- Give Burp a reduced OpenAPI 3.1 document so a pull request scan touches only approved, recoverable endpoints.
- Inject the DAST API key and application bearer token from CI secrets instead of committing them to YAML.
- Use the built-in CICD-optimized scan configuration for pull requests and reserve deeper custom scans for scheduled runs.
- Set a severity and confidence threshold in burp_config.yml so the container exit code becomes the release gate.
- Publish burp_junit_report.xml even when the scan fails so developers retain evidence and remediation guidance.
- Keep a stable correlation ID, a narrow scope, and a documented triage process to make scan trends trustworthy.
A useful burp suite api dast ci tutorial must do more than launch a scanner. It must define exactly which API operations Burp may exercise, authenticate with a disposable test identity, turn findings into a predictable build result, and preserve enough evidence for a developer to reproduce the problem. This guide builds that complete path with Burp Suite DAST 2026.6, OpenAPI 3.1, Docker, and GitHub Actions.
You will scan an authorized staging API, not production and not a third-party target. Burp Scanner sends non-standard and potentially state-changing requests, so use seeded records, reversible operations, rate controls, backups, and written permission. If you first need the desktop interception workflow, read using Burp Suite for QA before automating active scanning.
This implementation uses Burp Suite DAST, formerly Burp Suite Enterprise Edition, not a headless desktop edition. PortSwigger's container reads OpenAPI, returns correlated results to DAST, and writes portable JUnit evidence.
What You Will Build
By the end, you will have:
- A reduced OpenAPI 3.1 document containing only the staging endpoints approved for active scanning.
- A
burp_config.ymlfile that sets scope, bearer authentication, the CICD-optimized scan profile, reporting, and a release threshold. - A repeatable local Docker command for proving the integration before editing CI.
- A GitHub Actions job that runs on a suitably sized self-hosted runner and never writes tokens to logs or artifacts.
- A medium-and-firm quality gate plus a JUnit artifact that remains available on failed runs.
The same container and configuration work in other container-capable CI systems. Only secret syntax, workspace paths, artifact publication, and runner labels change.
Prerequisites
Use these reference versions for this tutorial:
| Component | Version or requirement | Why it matters |
|---|---|---|
| Burp Suite DAST | 2026.6 | Current DAST release at publication and the version used for the image tag |
| Docker Engine | 29.6.2, API 1.52 | Runs the official scanner image with current security fixes |
| Ubuntu | 24.04.3 LTS, x86-64 | Stable self-hosted runner platform for the commands below |
| GitHub Actions Runner | 2.329.0 or newer | Supports the Node 24 actions used by checkout@v6 and upload-artifact@v6 |
| Bash | 5.2 or newer | Executes the verification and container commands |
| jq | 1.8.1 | Validates OpenAPI JSON and constructs secret-bearing authentication JSON |
| libxml2-utils | 2.9.14 or newer | Supplies xmllint for JUnit verification |
PortSwigger recommends 4 CPU cores, 8 GB RAM, and 30 GB free disk. A standard GitHub-hosted Linux runner offers only 14 GB SSD, so use a self-hosted runner with enough capacity. Allow outbound access to PortSwigger's public ECR, the DAST server, the authorized target, and *.oastify.com on port 443.
You also need Burp Suite DAST or the licensed no-dashboard CI deployment. Create a DAST API user in the CI-driven scan initiator group, then create a separate low-privilege target identity with test-owned data. Store both credentials as CI secrets.
Confirm the command-line dependencies before continuing:
docker version --format 'Docker Server {{.Server.Version}}'
bash --version | head -n 1
jq --version
xmllint --version 2>&1 | head -n 1
df -h .
Verification: Docker reports 29.6.2 or an approved newer release, jq and xmllint return versions, and the filesystem containing the Docker data root has at least 30 GB free.
Step 1: Set Boundaries for This Burp Suite API DAST CI Tutorial
Write a scan authorization record before creating configuration. Name the target origin, approved paths and methods, excluded paths, scan identity, maximum request rate, test window, escalation contact, cleanup owner, and the database snapshot or reset strategy. Explicitly exclude logout, account deletion, payment capture, notification delivery, bulk export, infrastructure administration, and third-party hosts unless each action has its own safe test design.
Set non-secret shell variables for the staging target and the image that matches your DAST installation. Do not substitute latest casually. PortSwigger warns that a container version mismatched with the DAST server can produce incompatible configuration behavior. Upgrade the server and pinned image together.
export API_BASE_URL='https://staging-api.example.test'
export BURP_ENTERPRISE_SERVER_URL='https://dast.example.test'
export BURP_SCAN_IMAGE='public.ecr.aws/portswigger/enterprise-scan-container:2026.6'
test "${API_BASE_URL#https://}" != "$API_BASE_URL"
test "${BURP_ENTERPRISE_SERVER_URL#https://}" != "$BURP_ENTERPRISE_SERVER_URL"
curl --fail --silent --show-error --max-time 10 "$API_BASE_URL/health"
docker pull "$BURP_SCAN_IMAGE"
Replace both example origins with real, authorized values. The two test commands require HTTPS. The health request proves DNS, routing, TLS, and target availability from the same network where you are preparing the scan. The pull proves access to PortSwigger's public ECR repository.
Verification: curl exits 0 without a redirect to an identity provider, and docker image inspect "$BURP_SCAN_IMAGE" prints image metadata. If either fails, fix runner networking before adding a pipeline. Broader test selection should follow an explicit threat model such as the one in API security testing with OWASP.
Step 2: Create a Reduced OpenAPI Definition
Burp Suite DAST can scan OpenAPI JSON or YAML, Postman Collections, and SOAP WSDLs in a CI-driven API scan. It fully supports OpenAPI 3.1 and provisionally supports OpenAPI 3.2 in the current documentation. This tutorial uses JSON because jq can validate and modify it without adding another package.
Do not automatically feed the complete production contract into a pull request scan. Burp scans every endpoint referenced by the API definition, and the CI configuration cannot exclude an individual operation from that file. Create openapi-ci.json from an approved subset. The small example below describes health, order lookup, and order creation endpoints. Adapt the schemas and paths to your application.
cat > openapi-ci.template.json <<'JSON'
{
"openapi": "3.1.0",
"info": {
"title": "Orders API CI scan surface",
"version": "1.0.0"
},
"servers": [{ "url": "https://staging-api.example.test" }],
"security": [{ "bearerAuth": [] }],
"paths": {
"/health": {
"get": {
"security": [],
"responses": {
"200": { "description": "Service is ready" }
}
}
},
"/v1/orders/{orderId}": {
"get": {
"parameters": [{
"name": "orderId",
"in": "path",
"required": true,
"schema": { "type": "string", "example": "qa-order-1001" }
}],
"responses": {
"200": {
"description": "Test-owned order",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/Order" }
}
}
},
"404": { "description": "Order not found" }
}
}
},
"/v1/orders": {
"post": {
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["sku", "quantity"],
"properties": {
"sku": { "type": "string", "example": "QA-SKU-1" },
"quantity": { "type": "integer", "minimum": 1, "maximum": 5, "example": 1 }
}
}
}
}
},
"responses": {
"201": { "description": "Test order created" },
"400": { "description": "Invalid request" }
}
}
}
},
"components": {
"securitySchemes": {
"bearerAuth": { "type": "http", "scheme": "bearer" }
},
"schemas": {
"Order": {
"type": "object",
"required": ["id", "status"],
"properties": {
"id": { "type": "string" },
"status": { "type": "string", "enum": ["created", "paid", "cancelled"] }
}
}
}
}
}
JSON
jq --arg base "$API_BASE_URL" '.servers[0].url = $base' \
openapi-ci.template.json > openapi-ci.json
The authentication label bearerAuth is important. Burp uses that exact label to match a secret supplied later to the scheme declared in the document. Realistic examples improve request construction, while small quantity limits and test-prefixed identifiers reduce unwanted effects.
Verification: run the following structural assertions. Each must print true, and the final command must print only your staging origin.
jq -e '.openapi == "3.1.0"' openapi-ci.json
jq -e '.components.securitySchemes.bearerAuth.scheme == "bearer"' openapi-ci.json
jq -e '.paths | has("/v1/orders")' openapi-ci.json
jq -r '.servers[0].url' openapi-ci.json
Step 3: Configure Scope, Authentication, and the Gate
Create burp_config.yml in the repository root. The official container resolves the ${BURP_...} placeholders from environment variables. The file therefore contains policy and paths, while the secret values stay in the shell or CI vault.
enterpriseServer:
url: ${BURP_ENTERPRISE_SERVER_URL}
apiKey: ${BURP_ENTERPRISE_API_KEY}
site:
correlationId: ${BURP_CORRELATION_ID}
scope:
inScopeUrlPrefixes: ${BURP_SITE_IN_SCOPE_URL_PREFIXES}
outOfScopeUrlPrefixes: ${BURP_SITE_OUT_OF_SCOPE_URL_PREFIXES}
apiDefinition:
fromFile: ${BURP_SITE_API_DEFINITION_FILE_PATH}
authentications: ${BURP_SITE_API_DEFINITION_AUTHENTICATIONS}
scanConfigurations:
builtIn:
- "Crawl and Audit - CICD Optimized"
reporting:
reportFilePath: ${BURP_REPORT_FILE_PATH:-burp_junit_report.xml}
reportFormats: JUNIT
threshold:
minimumSeverity: MEDIUM
minimumConfidence: FIRM
enabled: true
inScopeUrlPrefixes is the hard visit boundary. The OpenAPI file chooses operations, and scope prevents discovered traffic from escaping the authorized API origin and version prefix. outOfScopeUrlPrefixes adds defense in depth for known dangerous paths. A stable correlation ID such as orders-api-pr lets DAST associate repeated results with the same site instead of creating one site per commit.
The threshold means an issue must meet both dimensions: severity of medium or higher and confidence of firm or higher. Burp still records lower-severity and tentative observations, but those do not produce the policy failure. Start with a reviewed threshold rather than INFO plus TENTATIVE, which often turns a first rollout into an unmanageable queue.
Verification: ask the pinned container for its own template and confirm that the configuration surface matches the installed release. Then inspect the local policy without printing secrets.
docker run --rm "$BURP_SCAN_IMAGE" --config-template \
| grep -E 'apiDefinition:|authentications:|minimumSeverity:'
grep -E 'CICD Optimized|minimumSeverity: MEDIUM|minimumConfidence: FIRM' \
burp_config.yml
If the generated template differs materially, stop and align the scan image with the DAST server before running an active scan.
Step 4: Run the Authenticated API Scan Locally
Test the exact container call on the intended runner network. Read both secrets without echo, construct the authentication array with jq, and keep shell tracing disabled. The application token is passed to the scheme named bearerAuth; the DAST key authenticates the scan container to the Burp server. They are different credentials with different permissions.
set +x
read -rsp 'Burp DAST API key: ' BURP_ENTERPRISE_API_KEY && printf '\n'
read -rsp 'Staging API bearer token: ' API_SCAN_TOKEN && printf '\n'
export BURP_ENTERPRISE_API_KEY API_SCAN_TOKEN
export BURP_CORRELATION_ID='orders-api-pr'
export BURP_SITE_API_DEFINITION_FILE_PATH="$PWD/openapi-ci.json"
export BURP_SITE_IN_SCOPE_URL_PREFIXES="$API_BASE_URL/v1/,$API_BASE_URL/health"
export BURP_SITE_OUT_OF_SCOPE_URL_PREFIXES="$API_BASE_URL/v1/admin/,$API_BASE_URL/v1/payments/capture"
export BURP_REPORT_FILE_PATH="$PWD/artifacts/burp_junit_report.xml"
export BURP_SITE_API_DEFINITION_AUTHENTICATIONS="$(
jq -cn --arg token "$API_SCAN_TOKEN" '[{label:"bearerAuth",token:$token}]'
)"
mkdir -p artifacts
docker run --rm --pull=always \
--user "$(id -u):$(id -g)" \
--volume "$PWD:$PWD:rw" \
--workdir "$PWD" \
--env BURP_CONFIG_FILE_PATH="$PWD/burp_config.yml" \
--env BURP_ENTERPRISE_SERVER_URL \
--env BURP_ENTERPRISE_API_KEY \
--env BURP_CORRELATION_ID \
--env BURP_SITE_API_DEFINITION_FILE_PATH \
--env BURP_SITE_API_DEFINITION_AUTHENTICATIONS \
--env BURP_SITE_IN_SCOPE_URL_PREFIXES \
--env BURP_SITE_OUT_OF_SCOPE_URL_PREFIXES \
--env BURP_REPORT_FILE_PATH \
"$BURP_SCAN_IMAGE"
Do not add || true. A nonzero container exit is the expected signal when the configured issue threshold is met. The mounted working directory makes the local definition and config visible inside the container and lets the unprivileged scanner user write the report back to artifacts. If your self-hosted DAST server uses a private CA, mount the full public certificate chain and provide it through the documented enterpriseServer.tlsCertificate setting or BURP_ENTERPRISE_SERVER_TLS_CERTIFICATE. Never solve that problem by disabling TLS verification.
Verification: regardless of the scan's pass or fail result, confirm that the report exists and is well-formed.
test -s artifacts/burp_junit_report.xml
xmllint --noout artifacts/burp_junit_report.xml
xmllint --xpath 'count(//testcase)' artifacts/burp_junit_report.xml
printf '\n'
A count greater than zero confirms that the JUnit document contains test cases. Also open the DAST dashboard and find orders-api-pr; the scan should show the same target, scope, and result. For deeper validation of how the bearer credential behaves, use the positive and negative cases in testing API key authentication.
Step 5: Prove Authenticated Coverage Before Trusting Findings
A successful container exit does not prove that protected operations were scanned. An expired token can leave Burp auditing only a public health endpoint and still produce a syntactically valid report. Establish a simple access oracle before each scan: the protected test object should reject an unauthenticated request and accept the dedicated scan token.
public_status="$(curl --silent --output /dev/null --write-out '%{http_code}' \
"$API_BASE_URL/v1/orders/qa-order-1001")"
auth_status="$(curl --silent --output /dev/null --write-out '%{http_code}' \
--header "Authorization: Bearer $API_SCAN_TOKEN" \
"$API_BASE_URL/v1/orders/qa-order-1001")"
test "$public_status" = '401'
test "$auth_status" = '200'
printf 'authentication oracle: public=%s authenticated=%s\n' \
"$public_status" "$auth_status"
Run this only against a test-owned object. If your API deliberately returns 404 to unauthorized users, assert that documented result instead of forcing 401. For a token with a short lifetime, use Burp's dynamicTokenConfig rather than creating a long-lived CI credential. The current configuration model can call a token endpoint, specify get or post, add headers and a body, extract a JSON field with a dot-separated path or XML with XPath, and refresh on a configured interval. Store the client secret in the CI vault and keep the token endpoint in scope only as required for authentication.
Review the scan event log or issue evidence for protected paths. At least one request should target /v1/orders/ with the intended identity, and repeated authentication failures should be absent. A large issue count is not proof of useful coverage. Endpoint reachability, correct role, and valid state are the coverage criteria.
Verification: the oracle prints public=401 authenticated=200, the DAST scan contains protected endpoint traffic, and the staging audit log attributes those requests to the dedicated scan identity.
Step 6: Add the Burp Suite API DAST CI Tutorial to GitHub Actions
Register a self-hosted GitHub runner with labels self-hosted, linux, x64, and dast. Give the runner network access only to the required destinations. Add repository or organization secrets named BURP_ENTERPRISE_API_KEY and API_SCAN_TOKEN, plus variables named BURP_ENTERPRISE_SERVER_URL and API_STAGING_URL. Protect the environment that owns those secrets if scans require approval.
Create .github/workflows/burp-api-dast.yml. It uses current Node 24 actions, read-only repository permissions, a protected environment, a 60-minute timeout, one concurrent scan per pull request, and evidence upload after failure.
name: Burp API DAST
on:
workflow_dispatch:
pull_request:
branches: [main]
paths:
- 'openapi-ci.json'
- 'burp_config.yml'
- 'src/**'
permissions:
contents: read
concurrency:
group: burp-api-dast-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
scan:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
runs-on: [self-hosted, linux, x64, dast]
environment: dast-staging
timeout-minutes: 60
env:
BURP_SCAN_IMAGE: public.ecr.aws/portswigger/enterprise-scan-container:2026.6
BURP_ENTERPRISE_SERVER_URL: ${{ vars.BURP_ENTERPRISE_SERVER_URL }}
BURP_ENTERPRISE_API_KEY: ${{ secrets.BURP_ENTERPRISE_API_KEY }}
API_SCAN_TOKEN: ${{ secrets.API_SCAN_TOKEN }}
API_BASE_URL: ${{ vars.API_STAGING_URL }}
steps:
- name: Check out source
uses: actions/checkout@v6
- name: Verify target and build authentication input
shell: bash
run: |
set -euo pipefail
test -n "$BURP_ENTERPRISE_SERVER_URL"
test -n "$BURP_ENTERPRISE_API_KEY"
test -n "$API_SCAN_TOKEN"
curl --fail --silent --show-error --max-time 10 "$API_BASE_URL/health"
jq --arg base "$API_BASE_URL" '.servers[0].url = $base' \
openapi-ci.template.json > openapi-ci.json
- name: Run Burp Suite DAST
shell: bash
run: |
set -euo pipefail
mkdir -p artifacts
auth_json="$(jq -cn --arg token "$API_SCAN_TOKEN" \
'[{label:"bearerAuth",token:$token}]')"
docker run --rm --pull=always \
--user "$(id -u):$(id -g)" \
--volume "$GITHUB_WORKSPACE:$GITHUB_WORKSPACE:rw" \
--workdir "$GITHUB_WORKSPACE" \
--env BURP_CONFIG_FILE_PATH="$GITHUB_WORKSPACE/burp_config.yml" \
--env BURP_ENTERPRISE_SERVER_URL \
--env BURP_ENTERPRISE_API_KEY \
--env BURP_CORRELATION_ID='orders-api-pr' \
--env BURP_SITE_API_DEFINITION_FILE_PATH="$GITHUB_WORKSPACE/openapi-ci.json" \
--env BURP_SITE_API_DEFINITION_AUTHENTICATIONS="$auth_json" \
--env BURP_SITE_IN_SCOPE_URL_PREFIXES="$API_BASE_URL/v1/,$API_BASE_URL/health" \
--env BURP_SITE_OUT_OF_SCOPE_URL_PREFIXES="$API_BASE_URL/v1/admin/,$API_BASE_URL/v1/payments/capture" \
--env BURP_REPORT_FILE_PATH="$GITHUB_WORKSPACE/artifacts/burp_junit_report.xml" \
"$BURP_SCAN_IMAGE"
- name: Upload Burp JUnit evidence
if: always()
uses: actions/upload-artifact@v6
with:
name: burp-api-dast-${{ github.run_id }}
path: artifacts/burp_junit_report.xml
if-no-files-found: error
retention-days: 14
The job condition skips forks, and the dast-staging environment should require approval. Never use pull_request_target to run untrusted changes with secrets. Do not print auth_json, enable set -x, or place tokens in OpenAPI. See CI secrets management for tests for rotation and least privilege.
Verification: trigger workflow_dispatch on a safe branch. The job must land on the dast runner, the DAST step must complete or fail specifically on the configured issue threshold, and the run summary must contain a downloadable burp-api-dast-<run-id> artifact.
Step 7: Read the JUnit Gate Correctly
The scanner's exit code is the gate. GitHub marks the DAST step failed when Burp reports at least one issue at medium-or-higher severity and firm-or-higher confidence. The always() artifact step then retains evidence, including requests, responses, and remediation material. Do not write a second parser that silently changes the policy unless your organization needs a separate reporting rule.
Download a report and inspect its aggregate failure count without exposing request bodies in logs:
xmllint --noout burp_junit_report.xml
failures="$(xmllint --xpath 'sum(//testsuite/@failures)' burp_junit_report.xml)"
tests="$(xmllint --xpath 'count(//testcase)' burp_junit_report.xml)"
printf 'Burp JUnit: tests=%s failures=%s\n' "$tests" "$failures"
test "$tests" != '0'
A failed gate deserves triage, not an automatic global ignore. Confirm the target, role, request, response, confidence, persisted side effect, and whether the issue is new, regressed, or already accepted. Reproduce the smallest safe exchange in Burp Repeater. If the finding is false, record the reason and use an exact issue name plus a narrow path regex in reporting.ignoredIssues. Names are case-sensitive. A bare issue name ignores that class everywhere, so it should require security review.
A passing scan means only that this scan, with this reachable surface, identity, configuration, and threshold, did not report a blocking issue. It does not prove absence of authorization flaws, race conditions, business logic abuse, unsafe asynchronous behavior, or vulnerabilities on omitted endpoints. Preserve contract tests, role matrices, code review, and focused manual testing alongside DAST.
Verification: a deliberately approved test case above the threshold makes the container nonzero and appears as a JUnit failure; after that controlled case is removed, the same workflow passes without changing the threshold. Never introduce a real vulnerability merely to test the gate. Use a disposable training target or a sanctioned scanner test fixture.
Step 8: Split Pull Request and Scheduled Scan Policies
Keep pull request feedback fast: use the reduced OpenAPI file, the CICD-optimized profile, deterministic records, and one scan per affected service. Cancel superseded runs.
For a scheduled scan, use a broader approved contract and a custom configuration exported from DAST or Professional. Reference its JSON under scanConfigurations.custom. If configurations conflict, the lower list item wins, so review their order.
Track why endpoints are absent. For example, a webhook receiver may be safe to scan only after signature validation, queue isolation, and replay cleanup are prepared. Build those controls with webhook signature verification testing, then add the endpoint intentionally.
When DAST is upgraded, update the pinned container tag, extract a fresh template with --config-template, compare configuration fields, and run the controlled gate check. Do not let latest change scanner behavior during an unrelated pull request.
Verification: the PR workflow exercises only the reduced definition, the scheduled workflow uses a different stable correlation ID, and each result is attached to the intended DAST site. Compare two clean runs to confirm stable authentication, coverage, and cleanup before making the status check mandatory.
Interview Questions and Answers
The interviewQnA field below contains seven model answers for this workflow. In an interview, connect each answer to an operational proof: the reduced contract defines coverage, the authentication oracle proves access, the container exit code enforces policy, and the retained JUnit file supports triage. Also explain why a passing DAST run is one security signal rather than a guarantee.
Best Practices
- Give the scan identity only the roles, tenant, objects, and methods needed for the approved contract.
- Keep create, update, and delete operations reversible, and assert cleanup after every run.
- Use one stable correlation ID per service and scan policy so dashboard trends compare like with like.
- Pin the DAST-aligned image tag, action major versions, runner image, and checked-in scan configuration.
- Store JUnit evidence under restricted retention because request and response content may contain sensitive test data.
- Add deeper roles as separate scans instead of giving one scanner identity every privilege.
- Measure coverage by reachable protected operations, not issue count or elapsed time.
- Review ignored issues, endpoint omissions, and tokens on a scheduled cadence.
Troubleshooting
Problem: The container reports an incompatible configuration or unknown field. -> Fix: Compare the DAST server release with the image tag, run that image with --config-template, and rebuild burp_config.yml from the matching template. Do not switch permanently to latest as a workaround.
Problem: The report contains only public endpoints. -> Fix: Confirm the OpenAPI security label exactly matches bearerAuth, rebuild BURP_SITE_API_DEFINITION_AUTHENTICATIONS with jq, run the 401/200 access oracle, and inspect target audit logs for the scan identity.
Problem: The scan follows links to an unauthorized host or path. -> Fix: Stop the scan, narrow inScopeUrlPrefixes, add explicit out-of-scope prefixes, remove unsafe operations from the CI OpenAPI file, and review redirects returned by the target. Scope is a safety control, not a discovery convenience.
Problem: burp_junit_report.xml is missing after a failed GitHub job. -> Fix: Mount the workspace read-write, set BURP_REPORT_FILE_PATH inside that mount, run the container with a UID that can write the artifact directory, and keep the upload step under if: always().
Problem: The DAST server connection fails with a certificate error. -> Fix: Supply the complete public certificate chain through enterpriseServer.tlsCertificate or BURP_ENTERPRISE_SERVER_TLS_CERTIFICATE. Verify the hostname and chain; never disable verification or use an unrelated CA bundle.
Problem: Every pull request remains blocked by an old accepted issue. -> Fix: Reproduce it, record the risk decision, and add the narrowest reviewed ignored-issue rule for that exact issue and path. Keep the finding visible in DAST, assign an expiry to the exception, and avoid lowering the global threshold.
Conclusion
A dependable API DAST gate combines four controls: a reduced contract, strict scope, a disposable authenticated identity, and an explicit severity-confidence policy. Burp Suite DAST supplies the scanner and evidence, but your configuration determines whether the result is safe, repeatable, and useful to developers.
Start with one service and a few recoverable endpoints. Prove network access, prove authentication, run the pinned container locally, publish JUnit on both pass and fail, then make the GitHub status check mandatory only after two stable clean runs and one sanctioned gate test.
Where To Go Next
Use Burp Suite for hands-on QA traffic analysis to reproduce a scanner finding in Proxy and Repeater. Expand coverage with OWASP-focused API security testing, harden the target credential using API authentication test cases, and review secrets management in CI before adding more environments. Then practice explaining the threat, evidence, false-positive decision, and release gate in /practice.
Interview Questions and Answers
How would you integrate Burp Suite DAST with an API pipeline?
I create a reduced OpenAPI contract for authorized staging operations, declare strict scope, and inject a dedicated application credential plus the DAST API key from CI secrets. The official scanner container runs on a suitably sized agent and writes JUnit. A severity-confidence threshold controls the exit code, while the report is always retained for triage.
Why do you use a separate OpenAPI file for pull request DAST?
A CI-driven API scan exercises every endpoint in the supplied definition. A reduced contract keeps feedback timely and prevents unsafe state-changing operations from entering the scan accidentally. The full authorized contract belongs in a scheduled policy with its own cleanup window.
How do you secure authentication in an API DAST job?
The DAST initiator key and target bearer token are distinct protected secrets with minimal roles and independent rotation. I construct the authentication JSON in memory, disable shell tracing, and avoid placing tokens in the repository or artifact. I also verify an authentication oracle before trusting scan coverage.
How do you choose a Burp DAST quality gate?
I begin with a threshold that blocks actionable confidence, such as medium severity and firm confidence, after a baseline review. I retain lower observations for triage rather than letting them fail every merge. Threshold changes and ignored issues require documented security review.
How do you handle a false positive from Burp in CI?
I reproduce the smallest request, inspect the actual target state, and document why the evidence does not establish the issue. If an exception is justified, I use the exact case-sensitive issue name and a narrow path regex. I keep the issue visible, assign an owner and expiry, and never apply an unreviewed global ignore.
What proves that a DAST scan had useful authenticated coverage?
The dedicated identity must pass a positive access check while an unauthenticated request is rejected. Scan evidence and application audit logs should show protected operations under that identity without repeated auth failures. Report generation or a zero finding count alone proves neither reachability nor role coverage.
Why run Burp DAST on a self-hosted GitHub runner?
PortSwigger recommends 4 CPU cores, 8 GB RAM, and 30 GB free disk for CI-driven scans. A standard hosted Linux runner currently offers only 14 GB SSD, so a controlled self-hosted runner better meets the storage recommendation and can have private staging network access. I also restrict runner egress and protect the environment that releases scan secrets.
Frequently Asked Questions
Can Burp Suite scan an OpenAPI definition in CI?
Yes. Burp Suite DAST CI-driven scans accept OpenAPI definitions in JSON or YAML, as well as Postman Collections and SOAP WSDLs. The current documentation fully supports OpenAPI 3.1 and provisionally supports OpenAPI 3.2.
Which Burp edition is required for this tutorial?
This workflow uses Burp Suite DAST or its licensed CI-driven deployment without a dashboard. It does not automate a desktop Burp Suite Professional installation or rely on an unofficial REST wrapper.
How does a Burp API DAST scan fail a CI build?
The `reporting.threshold` settings define minimum severity and confidence. If a finding meets both, the official scan container exits nonzero, while the JUnit report records evidence for CI publication and triage.
Where should I store the Burp DAST API key and application token?
Store them as separate protected CI secrets and inject them only into the scan process. Keep both out of the OpenAPI document, YAML file, repository history, shell tracing, console output, and retained artifacts.
Why did my authenticated Burp scan find only public endpoints?
The target token may be missing or expired, or its authentication label may not match the OpenAPI security scheme. Prove a rejected public request and a successful authenticated request against a seeded object, then confirm protected traffic in the scan evidence and application audit log.
Should I use the latest Burp scan container tag?
Pin the container version that matches your DAST server. PortSwigger notes that mismatched versions can make configuration templates incompatible; use `latest` only for a deliberate update check with `--pull=always`, not for an unreviewed release gate.
Is a passing Burp DAST scan proof that an API is secure?
No. It means the reachable surface did not produce a finding above the selected threshold under that identity and configuration. Authorization matrices, business logic tests, code review, contract tests, and manual investigation remain necessary.