July 23, 2026
Implementing “Shift Left, Verify Right” in a Vulnerable FinTech Microservices Application

By Lh1l0v3
6 min read
In my previous article, I introduced the concept of "Shift Left, Verify Right," a DevSecOps philosophy that emphasizes identifying security issues early in the Software Development Life Cycle (SDLC) while continuously validating that applications remain secure after deployment.
If you haven't read it yet, you can find it here: Shift Left, Verify Right: Building Security That Doesn't Slow Development
Understanding the philosophy is one thing. Implementing it in a real project is another.
As part of a DevSecOps implementation project, I was tasked with securing a deliberately vulnerable Python-based fintech microservices application by implementing a predefined security architecture. The objective was not to design the architecture from scratch, but to translate it into a working implementation using modern DevSecOps tools and practices.
Although the architecture provided a roadmap for the implementation, I quickly realized that effective DevSecOps begins before the first security scan runs. It begins during design.
This article walks through how I approached the project, the security controls I implemented, and the lessons I learned along the way.
The Challenge
The project simulated a modern fintech platform built using multiple Python microservices running on Kubernetes.
Rather than starting with a secure application, the services intentionally contained vulnerabilities commonly found in production environments. The objective was to implement security controls across the software delivery pipeline while maintaining the application's functionality.
The implementation covered multiple layers of security, including:
- Threat modeling
- CI/CD security
- Software supply chain security
- Infrastructure as Code security
- Kubernetes security
- Runtime security
- Observability
Together, these controls demonstrate that security is not a single product or a single scan. It is a continuous process that spans the entire software lifecycle.
Starting with Threat Modeling
Before configuring any security tools, I performed threat modeling to understand the application's attack surface and identify the risks that needed to be addressed.
Threat modeling is one of the earliest security activities in a secure SDLC because it takes place during the design phase, before applications are deployed.
Instead of asking which security scanners should be integrated into the pipeline, threat modeling begins by asking different questions:
- What assets are we trying to protect?
- Who are the potential attackers?
- How could they compromise the system?
- Which components present the greatest risk?
- Which security controls would reduce those risks?
For this fintech application, the critical assets included:
- User credentials
- JWT tokens
- Customer accounts
- Financial transactions
- Internal APIs
- PostgreSQL databases
- Containerized workloads
Potential threats included:
- SQL injection
- Broken authentication
- Weak JWT implementations
- Sensitive data exposure
- Secret leakage
- Container compromise
- Infrastructure misconfigurations
- Privilege escalation
- Unauthorized communication between services
Performing this exercise influenced every stage of the implementation. Rather than selecting security tools at random, each control addressed specific risks identified during the design phase.
This reinforced an important lesson.
Security tools are only effective when they are driven by risk.
Security Architecture
The provided architecture illustrates how security controls are integrated throughout the development lifecycle, from source code to runtime monitoring.
Figure 1. High-level DevSecOps architecture showing CI/CD security, software supply chain security, Kubernetes deployment, runtime protection, and observability.
Looking at the architecture, one thing becomes clear.
Security is layered.
Each control addresses a different stage of the application lifecycle, and together they create multiple opportunities to detect and reduce risk.
Securing the CI/CD Pipeline
Figure 2. GitHub Actions executing multiple automated security workflows after a pull request merge. Each workflow validates a different aspect of the application's security before deployment.
Every code change begins when a developer pushes code to GitHub. That action automatically triggers a GitHub Actions workflow responsible for executing several security checks before deployment.
Instead of relying on a single scanner, the pipeline combines multiple security tools that focus on different attack surfaces.
These include:
- GitLeaks
- SonarQube
- Trivy
- Checkov
- OWASP ZAP
- Cosign
- SBOM generation
Each tool contributes to a broader security strategy rather than attempting to solve every problem.
Secret Scanning with GitLeaks
One of the easiest ways to introduce a security incident is by accidentally committing secrets into source control.
GitLeaks scans the repository for exposed credentials such as:
- API keys
- Cloud credentials
- Private keys
- Passwords
- Access tokens
Detecting secrets before deployment prevents sensitive information from becoming permanently stored in Git history.
Static Application Security Testing with SonarQube
Static Application Security Testing analyzes source code without executing it.
SonarQube evaluates the application for insecure coding practices, potential vulnerabilities, and maintainability issues before software is deployed.
Examples include:
- SQL injection risks
- Weak cryptography
- Insecure coding patterns
- Code quality issues
- Security hotspots requiring manual review
Providing developers with immediate feedback makes vulnerabilities easier and less expensive to fix.
Dependency and Container Security with Trivy
Modern applications rely heavily on open source software. Even when custom code is secure, vulnerable dependencies can expose the application to attack.
Trivy scans:
- Python dependencies
- Operating system packages
- Container images
- Known CVEs
This enables vulnerable components to be identified and updated before deployment.
Infrastructure as Code Security with Checkov
Infrastructure should be treated as code and secured in the same way as application source code.
Checkov analyzes Terraform configurations for insecure infrastructure before cloud resources are provisioned.
Examples include:
- Publicly accessible services
- Excessive IAM permissions
- Missing encryption
- Weak networking configurations
Finding infrastructure issues before deployment helps prevent security misconfigurations from reaching production.
Dynamic Application Security Testing with OWASP ZAP
Static analysis identifies issues directly in source code, but some vulnerabilities only become visible while the application is running.
OWASP ZAP performs Dynamic Application Security Testing by interacting with the deployed application to identify runtime vulnerabilities such as:
- Cross Site Scripting (XSS)
- Security misconfigurations
- Missing security headers
- Session management issues
Combining static and dynamic testing provides broader security coverage than relying on either approach alone.
Security Gates
Scanning alone does not improve security. The results must influence deployment decisions. The pipeline implements security gates that evaluate scan results before allowing deployment to continue.
Critical vulnerabilities stop the pipeline, while lower severity findings generate warnings for further investigation. Security becomes part of the release process rather than an optional review.
Strengthening the Software Supply Chain
After the application passes the security gate, additional controls improve software integrity.
Software Bill of Materials
The pipeline generates a Software Bill of Materials that inventories every component included in the application.
Maintaining an SBOM makes it easier to determine whether an application is affected when new vulnerabilities are disclosed.
Container Image Signing
Before deployment, container images are digitally signed using Cosign.
Image signing helps verify that deployed images are authentic and have not been modified after the build process.
These controls strengthen trust throughout the software supply chain.
Deploying Securely on Kubernetes
Once the application passes all security checks, the container images are pushed to Amazon Elastic Container Registry before deployment to Amazon Elastic Kubernetes Service.
The Kubernetes environment includes several security controls, including:
- Admission policies
- Resource limits
- Label requirements
- Restrictions on privileged containers
- Network policies
These controls reduce the attack surface while enforcing consistent security standards across workloads.
Runtime Security
Deployment is not the end of security.
Applications continue to face new threats after they reach production.
Runtime controls provide continuous validation, representing the "Verify Right" portion of the DevSecOps philosophy.
Falco
Falco monitors container activity for suspicious behavior such as unexpected process execution, privilege escalation attempts, and other indicators of compromise.
HashiCorp Vault
Rather than storing secrets directly within application code or configuration files, credentials are managed securely through HashiCorp Vault.
Kubernetes Network Policies
Network policies follow a default deny approach that restricts communication between services unless explicitly allowed.
These controls help reduce lateral movement inside the cluster.
Observability
Security depends on visibility.
The architecture incorporates an observability stack consisting of:
- Prometheus for metrics collection
- Grafana for visualization
- Loki for centralized logging
- Alerting through Slack and PagerDuty
Together, these components provide operational insight while enabling faster detection and response to security events.
Lessons Learned
This project reinforced several important lessons.
Threat modeling should come before tool selection. Understanding the system and its risks provides context for every security control that follows.
No single security tool provides complete protection. Each scanner addresses a different layer of the attack surface, making defense in depth essential.
Automation significantly shortens the time between introducing a vulnerability and discovering it. Fast feedback allows developers to address issues before they become expensive production problems.
Finally, DevSecOps is not about adding as many security tools as possible. It is about integrating security into the software delivery process in a way that enables developers to build, test, and deploy software with greater confidence.
Conclusion
Implementing this security architecture gave me practical experience applying DevSecOps principles to a vulnerable fintech application.
More importantly, it demonstrated that security is most effective when it is continuous.
Threat modeling established security during the design phase.
Automated security checks reduced risk throughout development and deployment.
Runtime monitoring and observability ensured that security continued after the application was released.
That progression reflects the core idea behind modern DevSecOps.
Shift Left by identifying and addressing risks as early as possible.
Verify Right by continuously validating that security controls remain effective after deployment. Neither practice is sufficient on its own. Building resilient software requires both.
Resources
If you'd like to explore the implementation further, here is the project resources:
- GitHub Repository: https://github.com/Lhilove/SecureFlow-DevSecOps
What's Next
In the next article, I'll take a deeper look at the individual security tools used in this implementation, including GitLeaks, SonarQube, Trivy, Checkov, OWASP ZAP, and Cosign, and explain why each plays a different role in securing the software delivery pipeline.