Qualys WAS

Qualys WAS

Category: DAST
License: Commercial

Qualys Web Application Scanning (WAS) is an enterprise-grade cloud DAST platform that identifies vulnerabilities in web applications and APIs through automated dynamic testing.

As part of the broader Qualys Cloud Platform, WAS integrates with Qualys’s vulnerability management, policy compliance, and asset inventory capabilities to provide unified security visibility across web applications and infrastructure.

What is Qualys WAS?

Qualys WAS performs automated security testing of web applications by crawling sites and APIs, then probing for vulnerabilities by sending specially crafted requests.

The platform detects issues such as SQL injection, cross-site scripting (XSS), authentication flaws, and misconfigurations that attackers commonly exploit.

Being fully cloud-based, Qualys WAS requires no on-premises infrastructure for scanning external applications.

For internal applications, Qualys provides scanner appliances that can be deployed within private networks while still sending results to the cloud platform for centralized management and reporting.

The platform emphasizes scalability, supporting organizations with thousands of web applications through automated discovery, scheduled scanning, and centralized policy management.

Integration with the Qualys Cloud Platform enables correlation between web application vulnerabilities and infrastructure security findings.

Key Features

AI-Powered Scan Optimization

Qualys WAS uses machine learning to optimize scanning efficiency and accuracy.

The AI engine learns from scan results to reduce false positives, prioritize testing of likely vulnerability patterns, and adapt crawling behavior to different application architectures.

This optimization reduces scan times while maintaining thorough coverage, making regular scanning practical even for large application portfolios.

TruRisk Scoring

Rather than simply reporting vulnerability counts, Qualys WAS calculates TruRisk scores that quantify actual business risk.

TruRisk considers:

  • Vulnerability severity and exploitability
  • Asset criticality and business context
  • Threat intelligence about active exploitation
  • Remediation complexity and effort

This risk-based prioritization helps security teams focus on vulnerabilities that pose the greatest threat to the organization rather than chasing every finding.

Comprehensive Discovery

Qualys WAS automatically discovers web applications across your environment, identifying sites that may have been deployed without security team awareness.

Discovery can scan:

  • Public-facing applications via external scanning
  • Internal applications using scanner appliances
  • Cloud-hosted applications in AWS, Azure, and GCP
  • Subdomains and related web properties

Applications are automatically tagged and organized for granular reporting and access control.

API Security Testing

Beyond traditional web applications, Qualys WAS tests REST and SOAP APIs for security vulnerabilities.

The scanner can import OpenAPI (Swagger) specifications to understand API structure and test all documented endpoints systematically.

API testing covers OWASP API Security Top 10 vulnerabilities including broken object-level authorization, excessive data exposure, and injection flaws specific to API implementations.

Malware Detection

Qualys WAS includes behavioral malware detection that identifies when websites have been compromised and are serving malicious content.

This protects brand reputation by alerting organizations before search engines blacklist infected sites.

The malware scanner uses behavioral analysis to detect zero-day threats that signature-based scanners miss, providing early warning of website compromises.

How to Use Qualys WAS

Getting Started

Qualys WAS is accessed through the Qualys Cloud Platform.

After provisioning, you create web applications by specifying URLs and authentication details.

# Using Qualys API to create a web application
curl -X POST "https://qualysapi.qualys.com/qps/rest/3.0/create/was/webapp" \
  -H "Authorization: Basic ${QUALYS_CREDENTIALS}" \
  -H "Content-Type: application/xml" \
  -d '<?xml version="1.0" encoding="UTF-8"?>
      <ServiceRequest>
        <data>
          <WebApp>
            <name>Production Application</name>
            <url>https://app.example.com</url>
            <authRecord>
              <id>12345</id>
            </authRecord>
          </WebApp>
        </data>
      </ServiceRequest>'

Configuring Scans

# Launch a vulnerability scan
curl -X POST "https://qualysapi.qualys.com/qps/rest/3.0/launch/was/wasscan" \
  -H "Authorization: Basic ${QUALYS_CREDENTIALS}" \
  -H "Content-Type: application/xml" \
  -d '<?xml version="1.0" encoding="UTF-8"?>
      <ServiceRequest>
        <data>
          <WasScan>
            <name>Weekly Security Scan</name>
            <type>VULNERABILITY</type>
            <target>
              <webApp>
                <id>67890</id>
              </webApp>
            </target>
            <profile>
              <id>11111</id>
            </profile>
          </WasScan>
        </data>
      </ServiceRequest>'

# Check scan status
curl "https://qualysapi.qualys.com/qps/rest/3.0/status/was/wasscan/SCAN_ID" \
  -H "Authorization: Basic ${QUALYS_CREDENTIALS}"

Authentication Configuration

Qualys WAS supports multiple authentication methods for testing protected applications:

  • Form-based authentication: Record login sequences
  • HTTP Basic/Digest: Provide credentials directly
  • OAuth 2.0: Configure OAuth flows for API testing
  • Client certificates: Use certificates for mutual TLS
  • Custom headers: Add API keys or custom authentication tokens

Integration

GitHub Actions

name: Qualys WAS Scan
on:
  deployment:
    types: [completed]

jobs:
  security-scan:
    runs-on: ubuntu-latest
    if: github.event.deployment.environment == 'staging'
    steps:
      - name: Trigger Qualys WAS Scan
        run: |
          SCAN_RESPONSE=$(curl -s -X POST \
            "https://qualysapi.qualys.com/qps/rest/3.0/launch/was/wasscan" \
            -u "${{ secrets.QUALYS_USERNAME }}:${{ secrets.QUALYS_PASSWORD }}" \
            -H "Content-Type: application/xml" \
            -d '<?xml version="1.0" encoding="UTF-8"?>
                <ServiceRequest>
                  <data>
                    <WasScan>
                      <name>CI-CD-Scan-${{ github.sha }}</name>
                      <type>VULNERABILITY</type>
                      <target>
                        <webApp>
                          <id>${{ secrets.QUALYS_WEBAPP_ID }}</id>
                        </webApp>
                      </target>
                    </WasScan>
                  </data>
                </ServiceRequest>')

          SCAN_ID=$(echo "$SCAN_RESPONSE" | grep -oP '(?<=<id>)[^<]+')
          echo "SCAN_ID=$SCAN_ID" >> $GITHUB_ENV

      - name: Wait for Scan Completion
        run: |
          while true; do
            STATUS=$(curl -s \
              "https://qualysapi.qualys.com/qps/rest/3.0/status/was/wasscan/${{ env.SCAN_ID }}" \
              -u "${{ secrets.QUALYS_USERNAME }}:${{ secrets.QUALYS_PASSWORD }}" \
              | grep -oP '(?<=<status>)[^<]+')

            if [ "$STATUS" = "FINISHED" ]; then
              echo "Scan completed"
              break
            elif [ "$STATUS" = "ERROR" ] || [ "$STATUS" = "CANCELED" ]; then
              echo "Scan failed with status: $STATUS"
              exit 1
            fi
            sleep 60
          done

      - name: Check Findings
        run: |
          FINDINGS=$(curl -s \
            "https://qualysapi.qualys.com/qps/rest/3.0/count/was/finding" \
            -u "${{ secrets.QUALYS_USERNAME }}:${{ secrets.QUALYS_PASSWORD }}" \
            -H "Content-Type: application/xml" \
            -d '<?xml version="1.0" encoding="UTF-8"?>
                <ServiceRequest>
                  <filters>
                    <Criteria field="webApp.id" operator="EQUALS">${{ secrets.QUALYS_WEBAPP_ID }}</Criteria>
                    <Criteria field="severity" operator="GREATER">3</Criteria>
                  </filters>
                </ServiceRequest>')

          COUNT=$(echo "$FINDINGS" | grep -oP '(?<=<count>)[^<]+')
          if [ "$COUNT" -gt "0" ]; then
            echo "Found $COUNT high/critical severity vulnerabilities"
            exit 1
          fi

GitLab CI

stages:
  - deploy
  - security

variables:
  QUALYS_API_URL: "https://qualysapi.qualys.com/qps/rest/3.0"

qualys-was-scan:
  stage: security
  image: curlimages/curl:latest
  needs: [deploy-staging]
  script:
    - |
      # Launch scan
      RESPONSE=$(curl -s -X POST \
        "${QUALYS_API_URL}/launch/was/wasscan" \
        -u "${QUALYS_USERNAME}:${QUALYS_PASSWORD}" \
        -H "Content-Type: application/xml" \
        -d "<?xml version='1.0' encoding='UTF-8'?>
            <ServiceRequest>
              <data>
                <WasScan>
                  <name>GitLab-CI-${CI_PIPELINE_ID}</name>
                  <type>VULNERABILITY</type>
                  <target>
                    <webApp><id>${QUALYS_WEBAPP_ID}</id></webApp>
                  </target>
                </WasScan>
              </data>
            </ServiceRequest>")

      SCAN_ID=$(echo "$RESPONSE" | grep -oP '(?<=<id>)[^<]+' | head -1)
      echo "Started scan: $SCAN_ID"

      # Wait for completion
      while true; do
        STATUS=$(curl -s \
          "${QUALYS_API_URL}/status/was/wasscan/${SCAN_ID}" \
          -u "${QUALYS_USERNAME}:${QUALYS_PASSWORD}" \
          | grep -oP '(?<=<status>)[^<]+')

        echo "Scan status: $STATUS"

        if [ "$STATUS" = "FINISHED" ]; then
          break
        elif [ "$STATUS" = "ERROR" ]; then
          exit 1
        fi
        sleep 120
      done
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  timeout: 4h

Jenkins Pipeline

pipeline {
    agent any

    environment {
        QUALYS_CREDENTIALS = credentials('qualys-api-credentials')
        QUALYS_API_URL = 'https://qualysapi.qualys.com/qps/rest/3.0'
    }

    stages {
        stage('Deploy') {
            steps {
                echo 'Deploying to staging...'
            }
        }

        stage('Qualys WAS Scan') {
            steps {
                script {
                    // Launch scan
                    def launchResponse = httpRequest(
                        url: "${QUALYS_API_URL}/launch/was/wasscan",
                        httpMode: 'POST',
                        authentication: 'qualys-api-credentials',
                        contentType: 'APPLICATION_XML',
                        requestBody: """<?xml version="1.0" encoding="UTF-8"?>
                            <ServiceRequest>
                              <data>
                                <WasScan>
                                  <name>Jenkins-${BUILD_NUMBER}</name>
                                  <type>VULNERABILITY</type>
                                  <target>
                                    <webApp><id>${QUALYS_WEBAPP_ID}</id></webApp>
                                  </target>
                                </WasScan>
                              </data>
                            </ServiceRequest>"""
                    )

                    def scanId = (launchResponse.content =~ /<id>(\d+)<\/id>/)[0][1]
                    echo "Started Qualys WAS scan: ${scanId}"

                    // Poll for completion
                    def status = 'RUNNING'
                    while (status == 'RUNNING' || status == 'SUBMITTED') {
                        sleep(time: 2, unit: 'MINUTES')

                        def statusResponse = httpRequest(
                            url: "${QUALYS_API_URL}/status/was/wasscan/${scanId}",
                            authentication: 'qualys-api-credentials'
                        )

                        status = (statusResponse.content =~ /<status>(\w+)<\/status>/)[0][1]
                        echo "Scan status: ${status}"
                    }

                    if (status != 'FINISHED') {
                        error "Qualys WAS scan failed with status: ${status}"
                    }
                }
            }
        }
    }
}

When to Use Qualys WAS

Qualys WAS is well-suited for:

  • Enterprises already using Qualys Cloud Platform who want unified visibility across web applications and infrastructure
  • Organizations with large application portfolios that need scalable discovery and automated scanning
  • Security teams requiring risk-based prioritization through TruRisk scoring and business context
  • Regulated industries needing compliance reporting and audit trails

Qualys WAS may not be ideal for small organizations with limited budgets (other DAST tools offer lower entry points), teams needing deep authenticated testing of complex single-page applications (specialized tools may perform better), or organizations requiring fully on-premises deployment without any cloud connectivity.

For comprehensive application security, consider pairing Qualys WAS with SAST tools to identify vulnerabilities in source code before deployment and IAST tools for runtime analysis during testing.