Learn how to embed security into the development phase — covering SonarQube SAST with quality gates, Snyk and OWASP Dependency Check for SCA, CVSS vulnerability prioritization, and HashiCorp Vault dynamic secrets management including Kubernetes sidecar injection.
Imagine a developer writing a SQL query that concatenates user input directly into the query string. This is SQL injection — one of the most well-known vulnerabilities in software. It is also one of the easiest to prevent if caught early. If a code scanner catches it when the developer writes the line, the fix takes 5 minutes: swap concatenation for a parameterised query. If the same vulnerability is found during a security audit two months later, after the feature has been merged, tested, and integrated with three other systems, the fix involves revisiting code that nobody has touched in weeks, re-running tests, re-deploying to staging, and re-getting approval. IBM's research found that fixing a vulnerability found in development costs roughly 6 times less than fixing the same vulnerability found in production. This is the entire argument for shift left security: catch problems as early as possible, when they are cheapest and fastest to fix. Shift left security has three layers that build on each other: ``` Layer 1: SAST — Static Application Security Testing Scans source code for vulnerabilities as you write it Catches: SQL injection, XSS, insecure deserialization, hardcoded secrets When: On every commit and every PR Layer 2: SCA — Software Composition Analysis Scans your dependencies for known CVEs Catches: Log4Shell, vulnerable npm packages, outdated libraries When: On every build, automatically creates upgrade PRs Layer 3: Secrets Management — Vault Dynamic Credentials Eliminates static passwords entirely for applications Catches: Hardcoded DB passwords, long-lived API keys before they leak When: At application startup, credentials fetched fresh each deployment ``` This module builds all three layers from scratch. ---
SAST — Static Application Security Testing — analyzes your source code without executing it. It parses the code, builds a model of how data flows through the application, and identifies patterns that match known vulnerability types. ### What SAST Actually Does When you write this code in Java: ```java // Vulnerable — user input goes directly into SQL query String query = "SELECT * FROM users WHERE id = " + request.getParameter("id"); Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery(query); ``` A SAST tool parses this and traces the data flow: ``` request.getParameter("id") ← User-controlled input (tainted source) ↓ "SELECT * FROM users WHERE id = " + input ← Concatenated into SQL ↓ stmt.executeQuery(query) ← Executed as database command (dangerous sink) Result: SQL Injection vulnerability — untrusted data reaches a SQL sink without sanitisation ``` The secure version uses a parameterised query that SAST recognises as safe: ```java // Secure — parameterised query prevents injection String query = "SELECT * FROM users WHERE id = ?"; PreparedStatement stmt = connection.prepareStatement(query); stmt.setString(1, request.getParameter("id")); ResultSet rs = stmt.executeQuery(); ``` SAST checks hundreds of these patterns across the OWASP Top 10 and more. ### What SAST Catches — and What It Misses SAST is excellent at catching: * Injection vulnerabilities — SQL, command, LDAP, XPath * Cross-site scripting (XSS) * Insecure cryptography — using MD5 for password hashing, hardcoded keys * Missing authentication or authorisation checks * Dangerous function calls — `eval()`, `exec()`, `system()` SAST cannot catch: * Runtime misconfigurations — a correctly written app deployed with wrong settings * Business logic flaws — the code is correct but the logic is wrong * Vulnerabilities in dependencies — that is SCA's job * Authentication bypasses that only appear when the app is running — that is DAST's job SAST produces false positives. Not every flagged finding is a real vulnerability. This is why SonarQube's quality gates are valuable — they let you tune what actually blocks a build versus what goes into a backlog. ---
SonarQube is the most widely used SAST platform for enterprise teams. It integrates with every major CI/CD system, supports 30+ programming languages, and provides a dashboard showing security issues, code quality, and trend analysis over time. ### Run SonarQube with Docker ```bash # Start SonarQube — community edition is free and open source docker run -d \ --name sonarqube \ -p 9000:9000 \ -v sonarqube_data:/opt/sonarqube/data \ -v sonarqube_logs:/opt/sonarqube/logs \ sonarqube:lts-community # Wait 2-3 minutes for startup, then access at http://localhost:9000 # Default login: admin / admin (change this immediately) ``` ### Configure a Project ``` 1. Log in to SonarQube → Create Project → Local Project 2. Project display name: my-app 3. Project key: my-app (used in scanner configuration) 4. Click "Set Up" 5. Choose "Use the global setting" for new code definition 6. Click "Generate" to create an analysis token — save this token ``` ### Create sonar-project.properties Add this file to the root of your repository: ```properties sonar.projectKey=my-app sonar.projectName=My Application sonar.sources=src/main sonar.tests=src/test # Exclude generated code and third-party libraries from analysis sonar.exclusions=**/node_modules/**,**/vendor/**,**/*.min.js,**/target/** # For JavaScript/TypeScript projects # sonar.javascript.lcov.reportPaths=coverage/lcov.info ``` ### Integrate SonarQube with GitHub Actions ```yaml # .github/workflows/sonar-scan.yml name: SonarQube SAST Scan on: push: branches: [main, develop] pull_request: branches: [main] jobs: sonar: name: SonarQube Analysis runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # Full history for accurate blame and diff analysis # For Java projects — build first so bytecode is available - name: Set up JDK 17 uses: actions/setup-java@v4 with: java-version: 17 distribution: 'temurin' - name: Build project run: ./gradlew build # SonarQube scan - name: SonarQube Scan uses: sonarsource/sonarqube-scan-action@master env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} with: args: > -Dsonar.projectKey=my-app -Dsonar.sources=src/main -Dsonar.tests=src/test # Quality gate check — fails the build if gate fails - name: SonarQube Quality Gate Check id: sonarqube-quality-gate-check uses: sonarsource/sonarqube-quality-gate-action@master timeout-minutes: 5 env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} - name: Quality Gate Status run: echo "Quality Gate status is ${{ steps.sonarqube-quality-gate-check.outputs.quality-gate-status }}" ``` ### Configure Quality Gates Quality gates are the enforcement mechanism — they define what passes and what fails. SonarQube's default "Sonar Way" gate uses the Clean as You Code approach: it focuses on new code introduced in this PR or commit. The default gate fails when new code has: * Any new bugs * Any new security vulnerabilities * Any new security hotspots not reviewed * Code coverage on new code below 80% * Duplicate lines in new code above 3% For a DevSecOps team, a security-focused quality gate looks like: ``` In SonarQube: Quality Gates → Create Gate name: DevSecOps Security Gate Add conditions: Security Rating on New Code: is worse than A → FAIL Security Hotspots Reviewed on New Code: is less than 100% → FAIL Vulnerabilities on New Code: is greater than 0 → FAIL Reliability Rating on New Code: is worse than B → FAIL ``` This gate ensures no new security vulnerabilities or unreviewed hotspots can be merged. ### Reading SonarQube Findings When SonarQube flags an issue, the finding page shows: ``` Issue: SQL Injection Severity: Critical (Security) File: src/main/java/UserController.java Line: 47 Description: Change this code to not construct SQL queries directly from user-controlled data. Why it matters: Formatted SQL queries can be polluted with malicious SQL code by a user who is able to control the format string argument. A successful SQL injection attack can read sensitive data from the database or execute admin operations. How to fix it: Use parameterised queries or prepared statements. Example: PreparedStatement stmt = connection.prepareStatement("SELECT * FROM users WHERE id = ?"); Rule: java:S3649 (CWE-89) ``` Each finding links to the specific line, explains why it is dangerous, and shows how to fix it. Developers do not need security expertise — they follow the guidance. ---
Your application code is only a fraction of what runs in production. The npm packages, pip libraries, Maven dependencies, and Go modules you pull in are code you did not write, do not review, and may not monitor. Software Composition Analysis scans all of these for known CVEs. ### The Scale of the Problem The Equifax breach in 2017 compromised data on 147 million people. The root cause: an unpatched Apache Struts vulnerability (CVE-2017-5638) that had a publicly available exploit and a patch available. The team simply did not know they were running a vulnerable version. Log4Shell in 2021 was worse. Apache Log4j had a remote code execution vulnerability (CVE-2021-44228) that affected millions of applications. Companies with SBOMs and SCA tooling identified and patched within hours. Companies without them spent weeks manually inventorying their dependencies. ### Install Snyk ```bash # Install Snyk CLI npm install -g snyk # Authenticate (creates ~/.config/configstore/snyk.json) snyk auth # Test a Node.js project cd your-node-project snyk test # Test a Python project snyk test --file=requirements.txt # Monitor a project (continuous scanning, alerts when new CVEs appear) snyk monitor ``` ### Example Snyk Output ``` Testing my-payment-app... Found 3 vulnerabilities in 847 scanned packages 3 critical severity issues 0 high severity issues ✗ Critical severity vulnerability found in lodash Description: Prototype Pollution Info: https://snyk.io/vuln/SNYK-JS-LODASH-567746 Introduced through: lodash@4.17.4 Fixed in: lodash@4.17.21 ✗ Critical severity vulnerability found in axios Description: Server-Side Request Forgery (SSRF) Info: https://snyk.io/vuln/SNYK-JS-AXIOS-1579269 Introduced through: axios@0.19.0 Fixed in: axios@0.21.1 Organization: your-company Package manager: npm Target file: package.json ``` ### Snyk Fix PRs — Automated Remediation Snyk's most valuable feature is automatic fix pull requests. When Snyk detects a vulnerable dependency that has a patched version available, it opens a PR that bumps the version for you: ```bash # Generate fix PRs for all vulnerable dependencies snyk fix # Or configure in package.json scripts { "scripts": { "security-check": "snyk test --severity-threshold=high", "security-fix": "snyk fix" } } ``` ### Add Snyk to CI/CD ```yaml # .github/workflows/sca-scan.yml name: Dependency Vulnerability Scan on: push: branches: [main] pull_request: branches: [main] schedule: # Run daily — new CVEs are published every day - cron: '0 8 * * *' jobs: snyk: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Snyk Security Scan uses: snyk/actions/node@master env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: # Fail the build only for high and critical severity args: --severity-threshold=high --sarif-file-output=snyk.sarif # Upload findings to GitHub Security tab - name: Upload Snyk results to GitHub Code Scanning uses: github/codeql-action/upload-sarif@v3 with: sarif_file: snyk.sarif ``` ---
OWASP Dependency Check is the open-source alternative to Snyk — free, self-hosted, and widely used in enterprises that cannot use SaaS tools due to data residency requirements. It scans dependencies against the National Vulnerability Database (NVD) maintained by NIST. ### Maven Integration ```xml <!-- pom.xml --> <plugin> <groupId>org.owasp</groupId> <artifactId>dependency-check-maven</artifactId> <version>12.2.2</version> <configuration> <!-- Fail build if CVSS score is 7 or above (High severity) --> <failBuildOnCVSS>7</failBuildOnCVSS> <!-- Generate HTML report --> <format>HTML</format> <!-- Also generate JSON for pipeline processing --> <formats> <format>HTML</format> <format>JSON</format> </formats> <!-- Suppress false positives --> <suppressionFile>suppression.xml</suppressionFile> </configuration> <executions> <execution> <goals> <goal>check</goal> </goals> </execution> </executions> </plugin> ``` Run the scan: ```bash # Run dependency check as part of the build mvn dependency-check:check # Standalone scan without Maven build mvn dependency-check:check -DautoUpdate=false ``` ### npm / Node.js Integration ```bash # Using OWASP Dependency Check CLI dependency-check --project "my-app" \ --scan ./package.json \ --format HTML \ --out ./reports/ # Or use npm audit which also checks NVD npm audit --audit-level=high npm audit fix # Automatically fix where possible ``` ### GitHub Actions with OWASP Dependency Check ```yaml # .github/workflows/owasp-check.yml name: OWASP Dependency Check on: push: branches: [main] schedule: - cron: '0 6 * * 1' # Weekly Monday morning scan jobs: owasp: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: OWASP Dependency Check uses: dependency-check/Dependency-Check_Action@main with: project: 'my-app' path: '.' format: 'HTML' args: > --enableRetired --failOnCVSS 7 --out reports - name: Upload report uses: actions/upload-artifact@v4 if: always() with: name: dependency-check-report path: reports/ ``` ---
SCA tools find hundreds of vulnerabilities in a typical application. Not all of them need immediate action. CVSS — the Common Vulnerability Scoring System — gives you a standardised way to understand severity and prioritise your response. ### The CVSS Score Every CVE gets a CVSS score from 0.0 to 10.0: | Score | Severity | Response | |:------|:---------|:---------| | 9.0 – 10.0 | Critical | Fix immediately — same day | | 7.0 – 8.9 | High | Fix within 7 days | | 4.0 – 6.9 | Medium | Fix within 30 days | | 0.1 – 3.9 | Low | Fix in next scheduled update | | 0.0 | None | Informational only | ### What Goes Into a CVSS Score CVSS looks at three groups of metrics to calculate the score: **Base Metrics** — the intrinsic quality of the vulnerability: * Attack Vector — can the attacker exploit this remotely over the internet, or do they need local access? * Attack Complexity — is the exploit simple or does it require specific conditions? * Privileges Required — does the attacker need to be authenticated first? * User Interaction — does a user need to do something (click a link) for the exploit to work? * Impact on Confidentiality, Integrity, Availability — how bad is it if exploited? **Example — Log4Shell (CVE-2021-44228) got CVSS 10.0:** * Attack Vector: Network (exploitable over the internet) * Attack Complexity: Low (easy to exploit) * Privileges Required: None (no authentication needed) * User Interaction: None (fully automated) * Full impact on Confidentiality, Integrity, and Availability **Example — A low-severity dependency with CVSS 3.1:** * Attack Vector: Local (requires physical access or existing code execution) * Attack Complexity: High (specific conditions must be met) * Privileges Required: Admin (attacker must already be root) * Impact: Low information disclosure only ### CVSS vs EPSS — Two Ways to Prioritise CVSS tells you how bad a vulnerability is if exploited. EPSS (Exploit Prediction Scoring System) tells you how likely it is to actually be exploited in the wild within the next 30 days, based on real-world threat intelligence. Many teams combine both: ``` High CVSS + High EPSS → Fix today (dangerous AND attackers are using it right now) High CVSS + Low EPSS → Fix soon (dangerous but not being exploited yet) Low CVSS + High EPSS → Investigate (attackers like it, may be part of an attack chain) Low CVSS + Low EPSS → Schedule for next sprint (lowest priority) ``` ### The 95% Problem — Why Most CVEs Never Get Fixed OWASP's research found that 95% of vulnerable downloads had fixes already available. The problem is not that patches do not exist — it is that teams do not apply them. This is called corrosive risk — the vulnerability exists, the fix exists, but the team has not acted. The solution is automation: Dependabot, Snyk fix PRs, and Renovate create the upgrade PRs automatically. The team's job is to review and merge them, not to discover and create them. ---
Imagine a developer writing a SQL query that concatenates user input directly into the query string. This is SQL injecti...
SAST — Static Application Security Testing — analyzes your source code without executing it. It parses the code, builds ...
SonarQube is the most widely used SAST platform for enterprise teams. It integrates with every major CI/CD system, suppo...
Your application code is only a fraction of what runs in production. The npm packages, pip libraries, Maven dependencies...
OWASP Dependency Check is the open-source alternative to Snyk — free, self-hosted, and widely used in enterprises that c...
SCA tools find hundreds of vulnerabilities in a typical application. Not all of them need immediate action. CVSS — the C...
The Git and CI/CD Security modules introduced Vault. This section goes deeper — specifically on dynamic database credent...
Putting all three layers together into a single GitHub Actions workflow: ---...
This lab runs SAST and SCA against a deliberately vulnerable application to see real security findings. Part 1 — SAST wi...
Aligns directly with DevOps, Site Reliability (SRE), and Platform Engineering job descriptions.