- Introduction
- Setting Up the GitHub Actions Workflow
- Pipeline Overview
- Using Bandit for Python Security Scanning
- Building and Scanning Docker Containers with Docker Scout
- Additional Resources
- Conclusion and Future Steps
Introduction
Securing the CI pipeline is critical to ensuring the integrity of the code and the safety of the deployments. In this article, I'll show you how to build a secure CI pipeline using GitHub Actions and Docker Scout. We'll focus on the PyGoat repository, a Python application deliberately designed with security vulnerabilities. Our pipeline will use Bandit to scan the Python code and Docker Scout to ensure our Docker images are free from known vulnerabilities.
Setting Up the GitHub Actions Workflow
Setting up the workflow involves configuring GitHub Actions to automatically run security checks on every push to the repository. This not only streamlines our development process but also catches vulnerabilities early, helping us maintain a strong security posture.
To get started, we create a .github/workflows
directory in our app repository and add a YAML file (e.g., main.yml
) with the following content.
Pipeline Overview
Our main.yml file represents an overview of our CI pipeline, designed to perform both static application security testing (SAST) with Bandit and container image scanning with Docker Scout.
on: [push]
jobs:
sast_scan:
name: Run Bandit Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up python
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install Bandit
run: pip install bandit
- name: Run Bandit Scan
run: bandit -ll -ii -r . -f json -o bandit-report.json
- name: Upload Artifact
uses: actions/upload-artifact@v3
if: always()
with:
name: bandit-findings
path: bandit-report.json
image_scan:
name: Build Image and Run Image Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Docker
uses: docker/setup-buildx-action@v2
- name: Build Docker Image
run: docker build -f Dockerfile -t myapp:latest .
- name: Docker Scout Scan
uses: docker/scout-action@v1
with:
dockerhub-user: ${{ secrets.REPO_USER }}
dockerhub-password: ${{ secrets.REPO_PWD }}
command: quickview, cves
Key Components:
- sast_scan: This job runs Bandit, which scans the Python codebase for security vulnerabilities.
- image_scan: This job builds the Docker image and uses Docker Scout to scan it for vulnerabilities.
Using Bandit for Python Security Scanning
Bandit is an essential tool in this pipeline. It inspects our Python code for common security issues by analyzing the code’s abstract syntax tree (AST). Here's how Bandit is integrated into the CI pipeline:
Checkout Code: We start by pulling the latest version of the code from the repository.
Set up Python: Python 3.8 is configured in the environment.
Install Bandit: Bandit is installed using pip.
Run Bandit Scan: Bandit scans the entire codebase, generating a report in JSON format.
Upload Artifact: The JSON report is saved as an artifact for later review.

Bandit Scan Output Breakdown
The Bandit scan of the PyGoat repository identified several security issues in the codebase. Here are some of the most critical findings:
Use of yaml.load()
(B506)
- Location:
./introduction/lab_code/test.py:20:7
- Severity: Medium
- Confidence: High
- Issue: The
yaml.load()
function is unsafe because it allows the instantiation of arbitrary objects, leading to potential code execution vulnerabilities. - Recommendation: Replace
yaml.load()
withyaml.safe_load()
to prevent arbitrary object instantiation. - CWE: CWE-20: Improper Input Validation
- More Info: Bandit Documentation - yaml_load
Use of Insecure Hash Function (B303)
- Location:
./introduction/mitre.py:158:19
- Severity: Medium
- Confidence: High
- Issue: The code uses the MD5 hash function, which is considered insecure due to vulnerabilities that allow hash collisions.
- Recommendation: Use stronger hash functions like SHA-256.
- CWE: CWE-327: Use of a Broken or Risky Cryptographic Algorithm
- More Info: Bandit Documentation - MD5
Use of eval()
(B307)
- Location:
./introduction/mitre.py:215:17
- Severity: Medium
- Confidence: High
- Issue: The
eval()
function is potentially dangerous as it can execute arbitrary code. This poses a significant security risk. - Recommendation: Use
ast.literal_eval()
instead, which safely evaluates strings containing Python expressions. - CWE: CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
- More Info: Bandit Documentation - eval
Subprocess with shell=True
(B602)
- Location:
./introduction/mitre.py:230:14
and./introduction/views.py:423:26
- Severity: High
- Confidence: High
- Issue: Using
subprocess.Popen
withshell=True
is dangerous as it allows shell injection attacks. - Recommendation: Avoid using
shell=True
or sanitize the input carefully if you must use it. - CWE: CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
- More Info: Bandit Documentation - subprocess
Unsafe Use of pickle
(B301)
- Location:
./introduction/views.py:211:20
- Severity: Medium
- Confidence: High
- Issue: The use of
pickle.loads()
to deserialize data can be unsafe when handling untrusted input, leading to arbitrary code execution. - Recommendation: Avoid using
pickle
for deserialization unless absolutely necessary, and never with untrusted data. - CWE: CWE-502: Deserialization of Untrusted Data
- More Info: Bandit Documentation - pickle
Unsafe XML Parsing with xml.sax.make_parser()
and xml.dom.pulldom.parseString()
- Locations:
./introduction/views.py:250:13
and./introduction/views.py:252:10
- Severity: Medium
- Confidence: High
- Issue: These functions are vulnerable to XML attacks such as XML External Entity (XXE) attacks.
- Recommendation: Use safer alternatives like
defusedxml
to mitigate these vulnerabilities. - CWE: CWE-20: Improper Input Validation
- More Info: Bandit Documentation - XML Parsing
The Bandit scan effectively identified several critical security issues in your codebase. Addressing these issues by following the recommendations will significantly enhance the security of your application, reducing the risk of exploitation in production environments.
Docker Scout
Next, we check the container security aspect of the pipeline. After building the Docker image, Docker Scout scans it for vulnerabilities:
Checkout Code: The code is checked out again to ensure the latest version is used for the Docker build.
Set up Docker: Docker is configured for the build process.
Build Docker Image: The Docker image is built using the Dockerfile.
Docker Scout Scan: Docker Scout scans the newly built image for any known vulnerabilities, focusing on CVEs (Common Vulnerabilities and Exposures).

The Docker Scout scan of Docker image revealed a significant number of vulnerabilities across multiple packages. Below is a breakdown of the most critical and high-severity issues found during the scan.
Overview of Scan Results
- Target:
local://myapp:latest
- Digest:
b2573f4d3629
- Platform:
linux/amd64
- Total Vulnerabilities: 52 (3 Critical, 19 High, 17 Medium, 6 Low, 7 Unspecified)
- Packages Analyzed: 627
Notable Vulnerabilities
Critical Vulnerabilities
-
pyyaml
(CVE-2020-1747 and CVE-2020-14343)- Location:
pkg:pypi/pyyaml@5.1
- Severity: Critical
- Issue: The
pyyaml
package is affected by improper input validation vulnerabilities that could lead to code execution. - Affected Range:
<5.4
- Fixed Version:
5.4
- CVSS Score: 9.8
- More Info:
- Location:
-
django
(CVE-2023-31047)- Location:
pkg:pypi/django@4.1.7
- Severity: Critical
- Issue: A critical input validation issue in
django
that could allow attackers to exploit the system. - Affected Range:
<4.1.9
- Fixed Version:
4.1.9
- CVSS Score: 9.8
- More Info: CVE-2023-31047
- Location:
High Severity Vulnerabilities
-
pyyaml
(CVE-2019-20477)- Location:
pkg:pypi/pyyaml@5.1
- Severity: High
- Issue: Deserialization of untrusted data, which could lead to code execution.
- Affected Range:
>=5.1 <5.2
- Fixed Version:
5.2
- CVSS Score: 9.8
- More Info: CVE-2019-20477
- Location:
-
pillow
(CVE-2023-4863)- Location:
pkg:pypi/pillow@9.4.0
- Severity: High
- Issue: Out-of-bounds write vulnerability that could lead to code execution.
- Affected Range:
<10.0.1
- Fixed Version:
10.0.1
- CVSS Score: 8.8
- More Info: CVE-2023-4863
- Location:
-
django
(CVE-2023-46695)- Location:
pkg:pypi/django@4.1.7
- Severity: High
- Issue: Uncontrolled resource consumption, which could lead to denial of service (DoS).
- Affected Range:
<4.1.13
- Fixed Version:
4.1.13
- CVSS Score: 7.5
- More Info: CVE-2023-46695
- Location:
Key Takeaways
- Critical Vulnerabilities in
pyyaml
anddjango
: These packages have critical vulnerabilities that should be addressed immediately. Updating to the latest versions is strongly recommended. - High Number of High-Severity Issues: The scan found 19 high-severity vulnerabilities, which could pose significant risks if left unpatched.
- Action Items: Update all identified packages to their fixed versions. Consider using Docker Scout's recommendation and CVE view features to prioritize remediation efforts.
Next Steps
- View Vulnerabilities: Run
docker scout cves local://myapp:latest
to get detailed information on the vulnerabilities. - View Recommendations: Use
docker scout recommendations myapp:latest
to see base image update recommendations. - Secure Credential Storage: Address the warning about unencrypted password storage by configuring a credential helper, as described in the Docker documentation.
By taking these steps, you can significantly reduce the risk posed by the vulnerabilities identified in your Docker images and ensure a more secure deployment environment.
Additional Resources
Here are some resources for best security practices and tools to enhance the CI/CD pipeline:
- GitHub Actions Documentation: A comprehensive guide to setting up and managing workflows in GitHub Actions.
- OWASP Top Ten: Essential reading for understanding common security risks in web applications.
- Docker Security Best Practices: Learn how to secure Docker containers from the ground up.
- Trivy: An alternative container security scanner that provides comprehensive vulnerability detection.
- Snyk: A developer-first tool for finding and fixing vulnerabilities in dependencies, containers, and Infrastructure as Code (IaC).
Conclusion and Future Steps
By integrating Bandit and Docker Scout into the CI pipeline, we have automated a crucial aspect of our development workflow. These tools not only catch vulnerabilities in the code and containers but also provide a structured way to address them before they make it to production.
Next Steps:
- Broaden Security Checks: Integrate additional tools like Trivy for comprehensive container scanning or Snyk for dependency vulnerability checks.
- Automate Testing: Enhance the pipeline with automated tests to ensure code quality and functionality remain intact.
- Continuous Monitoring: Implement continuous monitoring strategies to stay ahead of new and emerging security threats.
This pipeline sets a solid foundation for securing the CI/CD process, ensuring the code and containers are safe, reliable, and ready for deployment.