Shift-Left in Software Security: Making Peace Between Developers and Security
When security sends a 300-finding report the day before release, nobody wins. Here's how to put security checks into the developer's flow without the noise.
In the classic model, security testing happened at the very end: build, test, then a scan or pentest just before release. The result is familiar: hundreds of findings, a squeezed schedule, "ship it for now", and developers who see security as the team that slows them down.
Shift-left means moving security checks left on the timeline, to the start of development. Fixing a flaw while writing the code is far cheaper than after release.
Why the conflict?
- Different goals: developers are measured on delivery, security on risk.
- Late feedback: findings on weeks-old code lack context.
- Noise: false positives destroy trust in every finding.
- Unclear ownership: who fixes it, and by when?
Tool families
| Type | Tests | Runs | Open source examples |
|---|---|---|---|
| SAST | Source code without running it | IDE, commit, PR | Semgrep, SonarQube Community, Bandit |
| SCA | Known vulnerabilities and licences in dependencies | PR, nightly | OWASP Dependency-Check, Trivy, osv-scanner |
| Secret scanning | Embedded passwords, keys, tokens | Pre-commit, PR | gitleaks, trufflehog |
| IaC scanning | Terraform, Kubernetes manifest issues | PR | Checkov, Trivy config |
| DAST | The running app from outside | After deploy to staging | OWASP ZAP, Nuclei |
Adding it to CI/CD: a practical example
name: security
on: [pull_request]
jobs:
static:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- name: Secret scan
uses: gitleaks/gitleaks-action@v2
- name: SAST (Semgrep)
run: |
pip install semgrep
semgrep scan --config p/owasp-top-ten --error --severity ERROR
- name: Dependency scan
run: |
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
trivy fs --scanners vuln --severity CRITICAL,HIGH --exit-code 1 .
dast:
needs: static
runs-on: ubuntu-latest
steps:
- name: ZAP baseline (staging)
uses: zaproxy/action-baseline@v0.12.0
with:
target: "https://staging.example.com"
Don't fail builds on every finding from day one. Run tools in report-only mode, clean up noise, then fail only on newly introduced critical findings. Pay down existing debt with a separate plan.
Golden rules for not wearing developers out
1. Bring feedback to where developers are
PR comments next to the relevant line, and IDE plugins before commit.
2. Show only the diff
Show findings introduced by this change, not five years of history.
3. Ruthlessly remove false positives
Tune rules per project; require a reason for suppressions and review them.
4. Show the fix
Give a safe code example, not just "SQL injection risk".
5. Be fast
Keep PR checks to a few minutes; move deep scans to nightly jobs.
Culture: security champions
A security-minded developer in each team bridges the two sides: facilitating threat modelling, tuning tool rules, bringing the developer view to security, backed by regular training.
Threat modelling: the leftmost point
Asking "how could this feature be abused?" at design time is the cheapest control. A 30-minute STRIDE session can prevent weeks of fixes.
What to measure
- Time to remediate critical findings.
- New vulnerability rate per release (should fall).
- False positive rate.
- Coverage: share of repositories with checks.
Shift-left doesn't remove shift-right
Runtime monitoring, WAFs, periodic pentests and bug bounties still catch what slips through. The ideal model checks in both directions.
Conclusion
Shift-left works when security helps developers do good work rather than burdening them. To add security checks to your development process or review existing code, see our software development service.
Are your systems truly secure?
Message us today for a free initial consultation. Let's assess your needs together.