Security reviews at the end of a release find problems when they are most expensive to fix. “Shift left” simply means running the same checks inside every pipeline run, so a leaked key or a vulnerable dependency fails the build the day it is introduced. Here is the set of stages I add to Java pipelines.
The stages
pipeline {
agent { label 'linux' }
environment {
IMAGE = "nexus.example.com:8443/apps/account-search:${BUILD_NUMBER}"
}
stages {
stage('Secrets scan') {
steps { sh 'gitleaks detect --source . --redact --exit-code 1' }
}
stage('Build & unit tests') {
steps { sh 'mvn -B clean verify' }
}
stage('SAST + quality gate') {
steps {
withSonarQubeEnv('sonar') { sh 'mvn -B sonar:sonar' }
timeout(time: 10, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}
stage('Dependency check') {
steps {
sh 'mvn -B org.owasp:dependency-check-maven:check -DfailBuildOnCVSS=7'
}
}
stage('Image build + scan') {
steps {
sh 'docker build -t $IMAGE .'
sh 'trivy image --exit-code 1 --severity HIGH,CRITICAL --ignore-unfixed $IMAGE'
sh 'trivy image --format cyclonedx --output sbom.json $IMAGE'
archiveArtifacts artifacts: 'sbom.json'
}
}
}
}
What each stage catches
- Secrets scan (gitleaks) – API keys, passwords and tokens committed to the repo. Run it first; it takes seconds.
- SAST with a quality gate (SonarQube) – injection risks, weak crypto and bugs in your code.
waitForQualityGatemakes the gate a hard stop instead of a dashboard nobody reads. - Dependency check (OWASP) – known CVEs in third-party libraries. Start with a CVSS threshold of 7 and tighten later.
- Image scan (Trivy) – vulnerable OS packages and runtimes in the final image.
--ignore-unfixedkeeps the build focused on things you can actually fix. - SBOM – a CycloneDX list of everything inside the image. When the next big library vulnerability is announced, you can answer “are we affected?” in minutes.
Making it stick
- Put these stages in the shared library, not in each
Jenkinsfile, so every team gets them and updates roll out in one place. - Pin scanner and tool versions and pull them through your Nexus proxy. Recent npm and PyPI compromises showed that floating tags like
latestare a supply-chain risk in themselves. - Have a documented exception process (suppression files with an owner and an expiry date). Otherwise people disable the stage the first time it blocks a release.
- Start in warning mode for a week, fix the backlog, then switch to failing builds.
The goal is not zero findings; it is that every new risk is visible, owned and decided on before it reaches production.