A professional, production-ready DevSecOps project demonstrating security vulnerability scanning integrated into a GitHub Actions CI/CD pipeline.
This project showcases Shift-Left Security β integrating security checks early in the development process through automated CI/CD pipelines. The pipeline automatically scans code for vulnerabilities when changes are pushed, preventing insecure code from reaching production.
- β Automated Security Scanning: Runs Bandit (Python SAST tool) on every push
- β Fail-Safe Pipeline: Blocks deployment if high-severity vulnerabilities are detected
- β Detailed Reporting: Generates JSON and text reports with vulnerability details
- β DevSecOps Best Practices: Demonstrates industry-standard security workflows
- β Beginner-Friendly: Simple, well-commented code and workflows
- β Production-Ready: Includes concurrency controls and proper error handling
secure-cicd/
β
βββ README.md # This file
βββ app.py # Sample vulnerable Python Flask app
βββ requirements.txt # Python dependencies
β
βββ .github/
βββ workflows/
βββ pipeline.yml # GitHub Actions workflow (CI/CD pipeline)
- GitHub account
- GitHub repository (public or private)
- Git installed locally
# On GitHub, create a new repository named "secure-cicd"
# (or clone this repository)# Option A: Clone if already created on GitHub
git clone https://github.com/<YOUR_USERNAME>/secure-cicd.git
cd secure-cicd
# Option B: Initialize locally and push to GitHub
git init
git remote add origin https://github.com/<YOUR_USERNAME>/secure-cicd.gitCopy the following files to your repository:
app.pyrequirements.txt.github/workflows/pipeline.yml
git add .
git commit -m "Initial commit: Add secure CI/CD pipeline"
git branch -M main
git push -u origin main- Go to your GitHub repository
- Click on the "Actions" tab
- You should see the workflow running
- Check the logs to see security scan results
A Flask web application intentionally containing security vulnerabilities for demonstration purposes:
Vulnerabilities Included:
β οΈ Hardcoded Credentials: Database password and API keys exposed in source codeβ οΈ Command Injection:subprocess.run()withshell=Trueand user inputβ οΈ Insecure Deserialization: Usingpickle.loads()on untrusted dataβ οΈ Debug Mode: Flask running withdebug=Truein production-like environmentβ οΈ Insecure Binding: App bound to0.0.0.0(all interfaces)β οΈ Information Disclosure: API endpoints exposing sensitive information
Purpose: Demonstrate what NOT to do, and show how Bandit detects these issues.
Specifies Python packages required by the application:
Flask==2.3.2 # Web framework
Werkzeug==2.3.6 # WSGI utilities
The main CI/CD pipeline configuration with two jobs:
Steps:
- Checkout code - Get repository code
- Setup Python 3.10 - Configure Python environment
- Display Python version - Verify setup
- Install Bandit - Install security scanner
- Full Bandit scan - Report all vulnerabilities
- Strict Bandit scan - Fail on high-severity issues
- Parse results - Generate human-readable report
- Upload report - Store as GitHub Actions artifact
- Check for critical issues - Fail build if needed
- Success message - Confirm all checks passed
Additional checks for Python dependencies:
- Verify
requirements.txtexists - Check for outdated/vulnerable packages using
pip-audit
Key Configuration:
- Trigger: Runs on push to
mainanddevelopbranches, and on PRs tomain - Concurrency: Prevents duplicate workflow runs
- Continue-on-error: Some steps don't block pipeline (informational only)
- Artifacts: Generates downloadable security reports
Bandit is a Python Static Application Security Testing (SAST) tool that scans code for common security issues.
# Run full scan (reports all issues)
bandit -r .
# Run strict scan (fails on HIGH severity)
bandit -r . -ll
# Generate JSON report
bandit -r . -f json -o report.json- π΄ HIGH: Critical security issues (e.g., hardcoded passwords)
- π MEDIUM: Significant concerns (e.g., weak cryptography)
- π‘ LOW: Minor issues (e.g., debug mode enabled)
Install and run Bandit on your machine:
# Install Bandit
pip install bandit
# Run scan on current directory
bandit -r .
# Run with strict settings
bandit -r . -ll -vWhen Bandit scans the vulnerable app.py, it should detect:
>> Issue: [B105:hardcoded_password_string] Possible hardcoded password
Severity: HIGH Confidence: MEDIUM
Location: app.py, line 12
>> Issue: [B602:shell_injection] A shell=True parameter was used with subprocess
Severity: HIGH Confidence: HIGH
Location: app.py, line 33
... (more issues)
After pushing to GitHub:
- Go to Actions tab in your repository
- Click on the workflow run
- Expand "Security Scan" job to see detailed logs
- Check Artifacts section to download the
bandit-security-report.json - Pipeline will fail due to detected vulnerabilities (as intended)
In pipeline.yml, change the Bandit severity level:
# Current: Fails on HIGH and above (-ll)
bandit -r . -ll
# Alternative options:
# -lll : Only CRITICAL issues (most lenient)
# -ll : MEDIUM and above
# -l : All issues including LOWExample: Add linting check with Pylint:
- name: Run Pylint
run: |
pip install pylint
pylint app.py || trueBandit scans all files by default. To exclude certain directories:
bandit -r . --exclude ".venv,tests,build"βββββββββββββββββββββββββββββββββββββββββββ
β Code Pushed to GitHub (main branch) β
ββββββββββββββββββββ¬βββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β GitHub Actions Triggered β
ββββββββββββββββββββ¬βββββββββββββββββββββββ
β
ββββββββββββ΄βββββββββββ
βΌ βΌ
βββββββββββββββ ββββββββββββββββββββ
β Security β β Dependencies β
β Scan Job β β Check Job β
ββββββββ¬βββββββ ββββββββ¬ββββββββββββ
β β
βββββββ΄βββββββββββββββββββ
β
βββΊ Checkout
βββΊ Setup Python
βββΊ Install Bandit
βββΊ Run Full Scan
βββΊ Run Strict Scan βββ
βββΊ Parse Results β
βββΊ Upload Report β
βββΊ Check Critical βββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β β FAIL (High severity issues found) β
β OR β
β β
PASS (No critical vulnerabilities) β
βββββββββββββββββββββββββββββββββββββββββββ
- Shift-Left Security: Security checks run early, not at deployment
- Automated Scanning: Human-free, consistent security reviews
- Fail-Safe Pipeline: Prevents insecure code from merging
- Reporting: Clear, actionable vulnerability reports
- Artifact Storage: Historical records for compliance/audit
- Concurrency Control: Prevents duplicate runs, saves resources
This project intentionally contains vulnerable code for educational purposes.
In a real application, you should:
- β Use secrets management (GitHub Secrets, AWS Secrets Manager)
- β Sanitize user inputs to prevent injection attacks
- β Use secure deserialization (JSON instead of pickle)
- β Disable debug mode in production
- β Apply least-privilege principles
- β Run security scanning regularly
- Bandit Documentation
- GitHub Actions Documentation
- OWASP Top 10 Security Risks
- DevSecOps Best Practices
Feel free to extend this project:
- Add more security tools (Snyk, Trivy, SonarQube)
- Implement code quality checks (Pylint, Black)
- Add performance testing
- Create deployment stages
- Add notifications (Slack, email)
This project is open source and available under the MIT License.
For questions or issues:
- Check the GitHub Actions logs
- Review Bandit documentation
- Consult GitHub Actions troubleshooting guides
Happy secure coding! π