Skip to content

Multi-Language Security Scanning

Microtec is a multi-platform system with backend services in .NET, frontends in Angular, and mobile apps in Flutter. Each technology stack has different package ecosystems and different vulnerability surfaces. The DevSecOps pipeline applies language-appropriate scanning tools to each layer.


Scanning Matrix

LayerLanguageDependency ScannerSASTContainer ScannerLinter
Backend.NET 8OWASP Dependency-CheckSonarCloudTrivyHadolint
FrontendTypeScript/Angularnpm audit + SnykSonarCloudTrivy (nginx image)Hadolint
MobileDart/Flutterpub auditN/A (no container)
InfrastructureBicep/YAMLBicep linter

.NET Backend

OWASP Dependency-Check

OWASP Dependency-Check (DC) scans NuGet package references against the National Vulnerability Database (NVD) and multiple other CVE sources.

yaml
- stage: DependencyCheck
  displayName: 'Stage 6 - Dependency Audit (.NET)'
  jobs:
    - job: OWASPDependencyCheck
      pool:
        vmImage: 'ubuntu-latest'
      steps:
        - task: Bash@3
          displayName: 'Run OWASP Dependency-Check'
          inputs:
            targetType: inline
            script: |
              docker run --rm \
                -v "$(Build.SourcesDirectory):/src" \
                -v "$(Build.ArtifactStagingDirectory):/report" \
                owasp/dependency-check:latest \
                  --project "Microtec ERP Backend" \
                  --scan /src/Platforms \
                  --format "HTML" \
                  --format "JSON" \
                  --out /report \
                  --failOnCVSS 7 \
                  --enableRetired \
                  --nvdApiKey "$(NVD_API_KEY)"

NVD API Key Required

OWASP DC requires an NVD API key for fast CVE data refresh. Without it, scans take 4–8 hours on first run. The key is stored in Key Vault and injected as $(NVD_API_KEY). Register at nvd.nist.gov/developers.

Threshold: Pipeline fails on any CVE with CVSS score ≥ 7.0 (High or Critical).

Suppression file: Known false positives are suppressed via devops/odc-suppressions.xml:

xml
<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
  <suppress>
    <notes>False positive: CVE-2021-XXXXX affects log4j, not our Microsoft.Extensions.Logging</notes>
    <cve>CVE-2021-XXXXX</cve>
  </suppress>
</suppressions>

SonarCloud (.NET)

SonarCloud SAST for .NET runs using the SonarScanner for .NET SDK. It analyses:

  • Code quality issues (bugs, code smells)
  • Security hotspots (SQL injection risks, insecure deserialization)
  • Code coverage (imported from test result XML)
  • Duplication percentage

See SonarCloud documentation for full configuration details.


Angular Frontend

npm audit

npm audit checks package-lock.json against the npm security advisory database. It runs automatically as part of the frontend build job:

yaml
- task: Bash@3
  displayName: 'npm audit (frontend deps)'
  inputs:
    targetType: inline
    workingDirectory: '$(Build.SourcesDirectory)/FrontApps'
    script: |
      npm ci
      npm audit --audit-level=high --json > $(Build.ArtifactStagingDirectory)/npm-audit.json
      # Exit non-zero if high or critical vulns found
      npm audit --audit-level=high

--audit-level=high means the pipeline fails on High or Critical vulnerabilities. Moderate and Low are reported but non-blocking.

Snyk

Snyk provides deeper analysis than npm audit, including transitive dependencies and license compliance:

yaml
- task: Bash@3
  displayName: 'Snyk scan (Angular)'
  env:
    SNYK_TOKEN: $(SNYK_TOKEN)
  inputs:
    targetType: inline
    script: |
      npx snyk test \
        --project-name="mic-erp-frontend" \
        --severity-threshold=high \
        --json \
        > $(Build.ArtifactStagingDirectory)/snyk-frontend.json || true

      npx snyk monitor \
        --project-name="mic-erp-frontend"

Snyk vs npm audit

Use both tools in parallel:

  • npm audit is fast and catches registry-known CVEs immediately
  • Snyk catches vulnerabilities not yet in the npm advisory database, and provides fix PRs

npm audit gates the build. Snyk is advisory (non-blocking) but feeds into the Snyk dashboard for trend monitoring.

SonarCloud (TypeScript/Angular)

SonarCloud analyses TypeScript source using the SonarScanner generic runner. It covers the same categories as the .NET scan: bugs, security hotspots, code smells, and coverage.


Flutter Mobile

pub audit

Flutter/Dart uses dart pub audit (available since Dart 2.19) to scan pubspec.lock for known vulnerabilities:

yaml
- task: Bash@3
  displayName: 'Dart pub audit (mobile deps)'
  inputs:
    targetType: inline
    workingDirectory: '$(Build.SourcesDirectory)/BoMobileApp'
    script: |
      flutter pub get
      dart pub audit --json > $(Build.ArtifactStagingDirectory)/pub-audit.json
      # Non-zero exit on any vulnerability
      dart pub audit

Flutter Security Ecosystem Maturity

The Dart/Flutter security advisory database is less mature than npm or NuGet. pub audit coverage is growing but may miss vulnerabilities that manual dependency review would catch. The mobile team reviews pubspec.lock changes in every PR as a compensating control.

Mobile apps are distributed as APK/IPA binaries (not containers), so Trivy image scanning does not apply. Instead, the build artefact is scanned with apkanalyzer for embedded secrets and mobsf (Mobile Security Framework) for mobile-specific issues.


Docker Images — Trivy + Hadolint

All services that produce container images are scanned with two tools.

Hadolint — Dockerfile Linting

Hadolint runs before the Docker build to catch insecure Dockerfile patterns:

yaml
- task: Bash@3
  displayName: 'Hadolint — Dockerfile lint'
  inputs:
    targetType: inline
    script: |
      docker run --rm \
        -v "$(Build.SourcesDirectory):/src" \
        hadolint/hadolint \
        hadolint \
          --failure-threshold error \
          --config /src/devops/hadolint.yaml \
          /src/Platforms/Dockerfile

devops/hadolint.yaml configuration:

yaml
failure-threshold: error
ignore:
  - DL3008   # apt-get version pinning — managed by base image
  - DL3009   # apt-get clean — handled in multi-stage build
trustedRegistries:
  - mcr.microsoft.com
  - ghcr.io

Trivy — Container Image Scanning

Trivy scans the built image after docker build but before docker push:

yaml
- task: Bash@3
  displayName: 'Trivy — image vulnerability scan'
  inputs:
    targetType: inline
    script: |
      docker run --rm \
        -v /var/run/docker.sock:/var/run/docker.sock \
        -v "$(Build.ArtifactStagingDirectory):/report" \
        aquasec/trivy:latest \
        image \
          --exit-code 1 \
          --severity HIGH,CRITICAL \
          --format json \
          --output /report/trivy-$(serviceName).json \
          "$(ACR_NAME).azurecr.io/$(serviceName):$(Build.BuildId)"

See Trivy documentation for full details on severity thresholds and base image policy.


Infrastructure — Bicep Linter

Bicep files undergo linting during the infrastructure pipeline:

bash
az bicep build --file main.bicep
az bicep lint --file main.bicep

The linter checks:

RuleDescription
no-unused-paramsRemove unused parameters
no-unused-varsRemove unused variables
prefer-interpolationUse string interpolation over concat()
secure-parameter-defaultParameters marked @secure() must not have default values
no-hardcoded-env-urlsDo not hardcode Azure environment URLs

Custom Bicep Rules

Custom rules enforcing Microtec naming conventions (e.g. resource name prefixes) are implemented as a pre-flight PowerShell validation script at devops/scripts/Validate-BicepNaming.ps1 rather than as native linter rules.


Scan Results Aggregation

All scan results (JSON format where available) are published as pipeline artefacts and ingested into the Security Dashboard in Azure DevOps. The dashboard tracks:

  • Open vulnerability count by severity across all services
  • Trend over last 30 pipeline runs
  • Mean time to remediate by severity tier

Internal Documentation — Microtec Platform Team