Appearance
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
| Layer | Language | Dependency Scanner | SAST | Container Scanner | Linter |
|---|---|---|---|---|---|
| Backend | .NET 8 | OWASP Dependency-Check | SonarCloud | Trivy | Hadolint |
| Frontend | TypeScript/Angular | npm audit + Snyk | SonarCloud | Trivy (nginx image) | Hadolint |
| Mobile | Dart/Flutter | pub audit | — | N/A (no container) | — |
| Infrastructure | Bicep/YAML | — | — | — | Bicep 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 auditis 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 auditFlutter 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/Dockerfiledevops/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.ioTrivy — 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.bicepThe linter checks:
| Rule | Description |
|---|---|
no-unused-params | Remove unused parameters |
no-unused-vars | Remove unused variables |
prefer-interpolation | Use string interpolation over concat() |
secure-parameter-default | Parameters marked @secure() must not have default values |
no-hardcoded-env-urls | Do 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