Application Security Testing: SAST, DAST & SCA

Build application security testing into development. Covers static analysis (SAST), dynamic testing (DAST), software composition analysis (SCA), security testing in CI/CD, and triage workflows.

Application security testing (AST) is a family of techniques applied during software development to detect and mitigate security vulnerabilities early and systematically. It matters most when building or maintaining a codebase where security is not an afterthought—especially in CI/CD pipelines, monorepos with multiple services, or systems with frequent releases. SAST, DAST, and SCA are the three pillars of AST: static analysis of source code, dynamic testing of running applications, and analysis of software components and their dependencies.

Static Application Security Testing (SAST)

SAST inspects source code without executing it, identifying security issues at the earliest stage of development. It runs against code in a repository, typically triggered by a pull request or on every commit.

Running SAST in CI

A typical SAST pipeline uses a combination of tools that analyze code for common vulnerabilities like SQL injection, XSS, insecure deserialization, and hard-coded secrets.


name: SAST
on: [pull_request, push]

jobs:
  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set up Java
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Run SonarQube Scanner
        run: |
          mvn sonar:sonar \
            -Dsonar.host.url=https://sonar.example.com \
            -Dsonar.login=abc123def456 \
            -Dsonar.projectKey=myapp \
            -Dsonar.sources=src \
            -Dsonar.exclusions=**/test/**,**/generated/**

      - name: Run CodeQL Analysis
        run: |
          codeql database create --language=java --source-root=src \
            codeql-database
          codeql database analyze codeql-database \
            --output=codeql-results.sarif \
            --format=sarif \
            --threads=4
          codeql github upload-results --sarif-file=codeql-results.sarif

The sonar:sonar Maven goal uploads results to a SonarQube server with a standard configuration. The codeql database create command generates a CodeQL database from the source tree. Key flags: --language selects the language-specific analysis, --source-root defines the base of the code, and --exclusions filters out test and generated files from analysis.

Common SAST Findings and Configuration

SAST tools report issues with precise locations: file, line, column, and a description. A typical report entry looks like:

{
  "ruleId": "java:S2068",
  "message": "Hard-coded password found",
  "locations": [
    {
      "physicalLocation": {
        "artifactLocation": {
          "uri": "src/main/java/com/example/auth/LoginService.java"
        },
        "region": {
          "startLine": 42,
          "startColumn": 15,
          "endLine": 42,
          "endColumn": 37
        }
      }
    }
  ],
  "properties": {
    "severity": "CRITICAL",
    "tags": ["security", "best-practice"]
  }
}

A common failure mode: SAST reports “Unvalidated input to SQL query” but misses a query that uses a parameterized PreparedStatement because the tool expects Statement or CallableStatement. The fix is to configure the tool to recognize PreparedStatement as valid input—either via a configuration file or command-line flag.

SAST Configuration Best Practices

  sonar.projectKey=myapp
  sonar.projectName=My Application
  sonar.sources=src
  sonar.exclusions=**/test/**,**/generated/**
  sonar.java.coveragePlugin=jacoco
  sonar.coverage.exclusions=**/test/**,**/generated/**
  sonar.scm.provider=git
  sonar.git.provider=github
  codeql database create --language=java,python --source-root=. --include=src
  # .codeql/config
  queries:
    - security
    - path-sensitivity
    - performance

Dynamic Application Security Testing (DAST)

DAST tests a fully deployed, running application by sending real HTTP requests and observing responses. It uncovers runtime vulnerabilities like misconfigured headers, insecure APIs, session management flaws, and broken access control.

Running DAST in a CI/CD Pipeline

DAST is most effective when executed against a staging or preview environment. It can be triggered by a deployment or as part of a post-deployment validation.

# Example: DAST with OWASP ZAP in a GitHub Actions workflow
name: DAST
on: [deployment]

jobs:
  zap:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Start web service
        run: |
          npm start &
          sleep 30  # Wait for service to boot

      - name: Run OWASP ZAP
        run: |
          docker run --rm \
            -v $(pwd)/zap-results:/zap/reports \
            -e ZAP_CONFIG_FILE=/zap/config/zap-config.json \
            owasp/zap2docker-weekly \
            -daemon \
            -host 0.0.0.0 \
            -port 8080 \
            -config "file:/zap/config/zap-config.json" \
            -config "scanner/active/scanPolicy=SecurityPolicy"

      - name: Run ZAP Scan
        run: |
          curl -X POST http://localhost:8080/JSON/core/action/scan/ \
            -H "Content-Type: application/json" \
            -d '{
              "url": "http://localhost:3000",
              "scanPolicyName": "SecurityPolicy"
            }'

      - name: Fetch Results
        run: |
          curl -X GET http://localhost:8080/JSON/core/view/alerts/ \
            -H "Accept: application/json" \
            -o alerts.json

      - name: Upload Reports
        run: |
          mkdir -p reports/zap
          cp alerts.json reports/zap/
          cp -r /zap/reports/*.html reports/zap/
          tar -czf reports/zap.tar.gz -C reports/zap .
          gh upload reports/zap.tar.gz

The docker run command starts ZAP in daemon mode, with a configuration file that defines scan policies and core settings. The curl command triggers a scan on a specific URL, and alerts.json contains a list of discovered vulnerabilities.

DAST Output and Interpretation

ZAP returns a standard JSON response for alerts:

{
  "alerts": [
    {
      "alert": "XSS - Reflected",
      "risk": "High",
      "confidence": "Medium",
      "description": "The application is vulnerable to reflected XSS attacks.",
      "param": "search",
      "attack": "test<script>alert(1)</script>",
      "evidence": "<input type=\"text\" name=\"search\" value=\"test<script>alert(1)</script>\" />",
      "uri": "https://staging.myapp.com/search",
      "source": "ZAP",
      "cwe": 79,
      "owasp": "A3",
      "solution": "Use input validation and output encoding."
    }
  ]
}

Each alert includes param for the vulnerable HTTP parameter, attack with the test payload, and evidence showing the actual HTML response where the attack was detected.

DAST Configuration and Pitfalls

  {
    "file": {
      "output": "/zap/reports"
    },
    "scanner": {
      "active": {
        "scanPolicy": "SecurityPolicy"
      }
    },
    "scanPolicy": {
      "SecurityPolicy": {
        "scan": [
          "all",
          "xss",
          "sqlinjection",
          "csrf",
          "insecure-headers"
        ],
        "config": {
          "xss": {
            "minLevel": "High",
            "maxTime": 60
          }
        }
      }
    }
  }

Software Composition Analysis (SCA)

SCA identifies and analyzes third-party libraries and dependencies in a project. It detects known vulnerabilities in dependencies, licenses, and outdated components.

Running SCA in CI

SCA is typically run after dependency resolution (e.g., npm install, mvn dependency:resolve, pip install).

# Example: SCA with Snyk in CI
name: SCA
on: [pull_request, push]

jobs:
  snyk:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm install

      - name: Run Snyk
        run: |
          snyk test --file=package.json \
            --json \
            --output=results.json \
            --org=myorg \
            --project-name=myapp

      - name: Check for Critical Vulnerabilities
        run: |
          jq -r '.[].vulnerabilities[] | select(.severity == "critical") | .id' results.json | \
            xargs -I{} snyk monitor --file=package.json --id={}

      - name: Upload Snyk Report
        run: |
          snyk monitor --file=package.json
          snyk report --file=results.json --format=html --output=report.html
          gh upload report.html

The snyk test command analyzes package.json and outputs a JSON report. It includes severity, title, description, references, and fixes.

SCA Output and Failure Modes

A typical SCA result:

{
  "vulnerabilities": [
    {
      "id": "SNYK-JS-EXPRESS-123456",
      "title": "Express: Remote Code Execution in Body Parser",
      "severity": "critical",
      "description": "A vulnerability in express-body-parser allows RCE via crafted JSON.",
      "package": "express",
      "version": "4.18.2",
      "fixedIn": [
        "4.19.0",
        "4.18.3"
      ],
      "references": [
        {
          "url": "https://github.com/expressjs/express/pull/4523",
          "title": "PR #4523: Add JSON body parser security hardening"
        },
        {
          "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-12345",
          "title": "CVE-2023-12345: RCE in Express"
        }
      ],
      "cvss": {
        "score": 9.8,
        "vector": "AV:N/AC:L/PR:N/UI:R/S:C/C:High/I:High/A:High"
      },
      "from": [
        "package.json",
        "package-lock.json"
      ],
      "install": {
        "path": "node_modules/express"
      }
    }
  ]
}

Key failure modes:

SCA Best Practices

  # snyk.yml
  org: myorg
  project: myapp
  monitor:
    enabled: true
    branch: main
    schedule: "0 0 * * *"
  test:
    severity: "critical"
    output: "json"
    file: "package.json"

Integration of SAST, DAST, and SCA

The most effective AST pipeline combines all three. A CI job might run:

  1. SAST with CodeQL and SonarQube
  2. DAST with ZAP on a deployed preview environment
  3. SCA with Snyk on the latest dependency graph

Results are aggregated into a single report, and failures in any component block the merge. A pull request might show:

Each tool runs independently but contributes to a unified view of the application’s security posture.

This page was rewritten on 16 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.