DevSecOps Governance (Part 3): Implementing Dynamic Application Security Testing (DAST) in Build…

Kieran HolmesDyn365CEYesterday21 Views

DevSecOps Governance (Part 3): Implementing Dynamic Application Security Testing (DAST) in Build Pipelines

Photo by Bernd 📷 Dittrich on Unsplash

Following on from my original blog When “Shift‑Left” Leaves the Back Door Open: Why Governance Matters More Than Ever‘ this is part 3 of a 3 part follow up series where I’ll discuss practical tools and strategies I’ve used to implement some of the security considerations I outlined in the aforementioned post.

In Part 1 I discussed Tooling, Secret Scanning, Branch and Security policies and pre-deployment gates. In Part 2 I discussed building SAST and SCA scanning into build pipelines.

In this final post I’ll dive deeper into Dynamic Application Security Testing (DAST) and how we can build in active security testing into our pipelines once our web applications have been deployed to our hosting environments.

Implementing DAST scanning into build pipelines

What is DAST and why do we need it?

DAST is all about testing the integrity and security of web applications post deployment. DAST is essentially designed to attempt to hack your website after you’ve deployed new changes and is typically triggered at the end of your build pipeline and will fail the build if any problems are discovered.

DAST is effective only if the application is running, iterating the various endpoints and looks for issues such as weak authentication, injection attacks (SQL), Cross-site scripting (XSS), Input validation, security header misconfigurations, server misconfigurations, runtime security vulnerabilities.

Many teams choose to build DAST into the build pipeline and runs AFTER the new web application has been deployed.

As DAST isn’t built into GitHub Advanced Security (I discussed GHAS in parts 1 and 2) it required a third party Open Source tool. In this example the tool of choice was OWASP Zap which is free, easy to configure and highly reputable.

Whilst the DAST execution logic is configured in the main build pipeline there is a dependency on a plan *.yaml file which acts as the DAST definition configuration.

The other key thing to remember is if your web application requires authentication — you will need to build this into the pipeline workstream. Playwright is good for this. You just need a test account with username and password (securely stored of course!).

If authenticated scanning is required, teams could use a dedicated non-privileged test account in a tightly controlled non-production environment, subject to organisational security policy and appropriate compensating controls. Any exceptions to standard authentication controls should be formally reviewed and approved by the relevant security stakeholders.

Below is an example of a DAST implementation I built into an application yaml build pipeline. The environmental variables below represent the key dynamic configuration values

  • WEBAPP_BASE_URL: The url of the website being tested
  • WEBAPP_LOGIN_ENDPOINT: The specific authentication endpoint for the url being tested
  • TEST_USER_NAME: The user name for the test login account
  • TEST_USER_PASSWORD: The password for the test user account

Example DAST snippet. Run this after your code has deployed at the end of your yaml pipeline

# ============================================================
# DAST Stage (Authenticated via Browser Automation)
# ============================================================

##This scan is configured NOT to RUN on PR commits

- stage: DAST_SCAN
displayName: "DAST Scan (Authenticated)"
condition: ne(variables['Build.Reason'], 'PullRequest')

variables:
- group: webAppAuthSecrets # <-- Variable group containing credentials + app URLs for this environment

jobs:
- job: DAST_TEST
displayName: "Run Authenticated DAST Scan"
pool:
vmImage: 'ubuntu-latest'

steps:
- checkout: self

# ------------------------------------------------------
# Install Node + Playwright Browser Automation Framework
# ------------------------------------------------------
- task: NodeTool@0
inputs:
versionSpec: '18.x'
displayName: "Install Node.js"

- script: |
npm install -D playwright
npx playwright install --with-deps chromium
displayName: "Install Browser Automation Dependencies"

# ------------------------------------------------------
# STEP 1 — Authenticate using a scripted browser login
# Produces an authenticated session cookie or token and runs in a headless browser session
# Make sure you have a Playwright browser-login.js file with login logic located at the 'security/auth/' directory
# Make sure you have a DAST configuration file dast-plan.yaml located at the 'security/dast/' directory
# ------------------------------------------------------
- script: |
set -e
echo "Running scripted login to obtain session..."

node security/auth/browser-login.js

AUTH_COOKIE=$(cat auth_cookie.txt)
if [ -z "$AUTH_COOKIE" ]; then
echo " Authentication step produced no session token/cookie"
exit 1
fi

echo "##vso[task.setvariable variable=AUTH_COOKIE]$AUTH_COOKIE"
echo "Authentication complete."
displayName: "Run Authenticated Browser Login"
env:
WEBAPP_BASE_URL: $(WEBAPP_BASE_URL)
WEBAPP_LOGIN_ENDPOINT: $(WEBAPP_LOGIN_ENDPOINT)
TEST_USER_NAME: $(TEST_USER_NAME)
TEST_USER_PASSWORD: $(TEST_USER_PASSWORD)

# ------------------------------------------------------
# STEP 2 — Load DAST Scan Plan
# ------------------------------------------------------
- script: |
set -e
PLAN_SRC="security/dast/dast-plan.yaml"
PLAN_DST="$(Pipeline.Workspace)/dast-plan.yaml"

if [ ! -f "$PLAN_SRC" ]; then
echo " Missing scan plan configuration: $PLAN_SRC"
exit 1
fi

cp "$PLAN_SRC" "$PLAN_DST"
echo "----- DAST Scan Plan -----"
cat "$PLAN_DST"
displayName: "Load DAST Scan Plan"

# ------------------------------------------------------
# STEP 3 — Execute DAST Scan Container
# Generic: replace with any DAST engine container.
# Runs as a docker container
#-u: ensures process runs as root inside the container so that directories can be written too etc
#-e: grabs and sets the authentication context for the logged in user via the cookie obtained from the Playwright login step earlier and also sets the SUT url
#-v: mounts the working pipeline in the container and sets where to output the results of the scan
#scan.sh: loads the scan plan, configures the authentication headers, runs spidering, sets attack levels i.e. active or passive (active is a more aggressive scan form then passive
# ------------------------------------------------------
- script: |
set -e
mkdir -p "$(Pipeline.Workspace)/TestResults"

echo "Running DAST scan against target: $(WEBAPP_BASE_URL)"
TARGET_HOST=$(echo $(WEBAPP_BASE_URL) | sed -E 's#https?://([^/]+)/?.*#1#')

docker run --rm
-u 0:0
-e AUTH_HEADER_NAME="Cookie"
-e AUTH_HEADER_VALUE="$(AUTH_COOKIE)"
-e AUTH_HEADER_DOMAIN="$TARGET_HOST"
-v "$(Pipeline.Workspace)":/scan/work
-v "$(Pipeline.Workspace)/TestResults":/scan/output
$(DAST_ENGINE_IMAGE)
scan.sh --plan /scan/work/dast-plan.yaml --loglevel DEBUG
2>&1 | tee "$(Pipeline.Workspace)/dast_output.log"

echo " DAST scan complete."
displayName: "Run DAST Scan (Authenticated)"

# ------------------------------------------------------
# STEP 4 — Fail Only on High Severity Findings
# Generic XML/JSON parsing to detect critical results.
# ------------------------------------------------------
- script: |
set -e
REPORT="$(Pipeline.Workspace)/TestResults/dast-report.xml"

if [ ! -f "$REPORT" ]; then
echo " Missing DAST report: $REPORT"
tail -n 200 "$(Pipeline.Workspace)/dast_output.log" || true
exit 1
fi

echo "Scanning DAST report for HIGH severity issues..."
if grep -q "<riskcode>3</riskcode>" "$REPORT"; then
echo " High severity vulnerabilities detected!"
exit 1
fi

echo " No HIGH severity vulnerabilities found."
displayName: "Fail Only on HIGH Severity"

# ------------------------------------------------------
# STEP 5 — Publish Results
# ------------------------------------------------------
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: "$(Pipeline.Workspace)/TestResults"
ArtifactName: "DAST-Scan-Results"
publishLocation: "Container"
displayName: "Publish DAST Results"

An example of the Playwright login file (referred to as browser-login.js in the pipeline logic). This does the heavy lifting of logging into the website, and generating the authentication cookie for DAST to reuse and authenticate

Example of the DAST plan *.yaml file (referred to as the dast-plan.yaml in the DAST pipeline snippet). Sets configuration values for the test url, the authentication type, whether it’s active or passive testing (or both), where to output the report, and what criteria to fail on.

env:
contexts:
- name: testmysite
urls:
- "https://www.mytestsite.com/"
includePaths:
- "https://www.mytestsite.com/.*"
authentication:
method: "manual"
sessionManagement:
method: "cookie"

jobs:
# -------------------------------------------
# Crawl the web site
# -------------------------------------------
- type: spider
parameters:
context: "testmysite"
maxDuration: 3

# -------------------------------------------
# Wait for passive scanning to finish
# -------------------------------------------
- type: passiveScan-wait
parameters:
maxDuration: 180

# -------------------------------------------
# Active Scan (full attack)
# -------------------------------------------
- type: activeScan
parameters:
context: "testmysite"
maxRuleDurationInMins: 5

# -------------------------------------------
# Report output
# /zap/output is mounted from $(Pipeline.Workspace)/TestResults
# -------------------------------------------
- type: report
parameters:
template: "traditional-xml"
reportDir: "/zap/output"
reportFile: "active-report"

# -------------------------------------------
# Exit Status (Medium triggers warning)
# FAIL pipeline on High (handled in YAML stage)
# -------------------------------------------
- type: exitStatus
parameters:
errorLevel: "High"
warnLevel: "Medium"
okExitValue: 0
errorExitValue: 1
warnExitValue: 2

Once the results of the scan have been generated you can find them in the published artifacts as an active-report.xml file.

Summary

In summary this was the final part of a three part series where I’ve discussed DevSecOps governance and the implementation of Dynamic Application Software Testing (DAST) within build pipelines for the purpose of testing the integrity and security of newly deployed web application. I hope you find this helpful on your journey towards a shift-left mind set.

Originally published at https://techmusings.co.uk on March 27, 2026.

If you want to learn more about the Microsoft Team here at Capgemini, take a look at our open roles and consider joining the team!


DevSecOps Governance (Part 3): Implementing Dynamic Application Security Testing (DAST) in Build… was originally published in Capgemini Microsoft Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.

Original Post https://medium.com/capgemini-microsoft-team/devsecops-governance-part-3-implementing-dynamic-application-security-testing-dast-in-build-641c89d6901c?source=rss—-333ebfdadb74—4

0 Votes: 0 Upvotes, 0 Downvotes (0 Points)

Leave a reply

Join Us
  • X Network2.1K
  • LinkedIn3.8k
  • Bluesky0.5K
Support The Site
Events
July 2026
MTWTFSS
   1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31   
« Jun   Aug »
Follow
Search
Loading

Signing-in 3 seconds...

Signing-up 3 seconds...

Discover more from 365 Community Online

Subscribe now to keep reading and get access to the full archive.

Continue reading