Exploring secureCodeBox — An Open-Source Continuous Security Testing Solution for DevSecOps

A Comprehensive Review of secureCodeBox — an Open-Source Platform for Continuous Security Utilizing Popular Testing Tools. Presenting architecture, configuration, example usage and potential uses cases of the platform.

Krzysztof Pranczk
ITNEXT

--

In a comment on my recent article about Vulnerability Management, one reader asked about secureCodeBox. At the time of reading the comment, I had no idea what secureCodeBox was, so I visited the official website. There, I found a really interesting description stating that the solution integrates multiple widely-used security scanners for continuous security testing, and the project is open-source. As I’m a curious person and this solution seemed promising for DevSecOps use cases, I really wanted to give it a try.

secureCodeBox Logo

In this publication, you will learn what secureCodeBox is, its use cases in the context of DevSecOps, and how it can be integrated within your organization.

Introduction to secureCodeBox

Description

I really enjoy reading project descriptions shared on GitHub repository pages. Many of these descriptions are unique and explain projects in a very short, yet accurate way. In this case, we can read:

secureCodeBox is a kubernetes based, modularized toolchain for continuous security scans of your software project. Its goal is to orchestrate and easily automate a bunch of security-testing tools out of the box.

I was especially interested about the “continuous security scans” and “easily automate […] security-testing tools out of the box” parts. In a modern development environment, Continuous Integration (CI) and Continuous Delivery (CD) pipelines are crucial for effectively delivering software changes to end users. The classic approach of performing security testing after deployment is no longer effective, as deployments may occur tens or hundreds of times per day. In such environments, solutions like secureCodeBox could be integrated within CI/CD pipelines to automatically scan changes and provide findings to developers so they can fix issues before deployment. In this way, security testing can be scaled up without relying on manual security reviews. However, it should be noted that the classic approach of manual security testing performed by penetration testers remains important, as automation may not detect sophisticated security issues.

Architecture

The architecture of secureCodeBox is presented below:

secureCodeBox — Architecture Diagram

Based on the architecture diagram, we can observe that the main scanning activities are performed within the Scanner Container by a Kubernetes Job in step 2. This container is used as an environment to run scanning activities. If you’re not familiar with Kubernetes (aka K8s), a Kubernetes Job represents one-off tasks that run to completion and then stop, using pods to execute these tasks. A pod is one or more containers running within the K8s ecosystem. This Kubernetes Job also uses a Lurker container, which is responsible for extracting results from the Scanner Container and passing them to the Parser Container at step 3 — another Kubernetes Job. Once the results are parsed into the correct format, they are sent to two additional Kubernetes Jobs in steps 4 and 5 to modify and persist the scanner’s results.

With Kubernetes Jobs, it’s possible to save resources between scanning activities as they can be spun up on-demand and utilize resources only when needed. Another advantage of this approach is that all unnecessary scanning artifacts or metadata are deleted between Kubernetes Jobs executions.

The main component responsible for handling this flow is the secureCodeBox Operator. This Operator orchestrates the scans by triggering the appropriate Kubernetes Jobs for each step, starting from scanning activities, parsing the results, and ending with modifying and persisting findings.

In my opinion, this is a pretty decent architecture for scanning activities. It’s also scalable and allows for the easy addition of more scanners as new Kubernetes objects.

Deploying secureCodeBox

SecureCodeBox can be deployed using Helm charts in Kubernetes. I find Helm to be a really effective way to deploy various solutions in K8s. It doesn’t require much deployment effort, and deployed objects can be easily adjusted with Helm variables.

For the purposes of this article, I’m using minikube to create a local Kubernetes cluster. The idea of Minikube is to allow developers to create an environment that can be effectively used for local development of K8s applications. However, it should be noted that Minikube is not designed for production use cases. If you read my articles, you’ll notice that I often use it for testing various tools deployed in K8s.

Let’s start Minikube with 4 CPUs and 2048 MB of memory with the following command:

minikube start --cpus=4 --memory=2048m

With Minikube up and running, we can add Helm repositories using the command shown below:

helm repo add secureCodeBox https://charts.securecodebox.io

I strongly suggest creating a separate Kubernetes namespace to separate secureCodeBox objects from other K8s objects, especially if other services are deployed in K8s. This will make it easier to manage the newly created objects dedicated to this platform. A new K8s namespace can be created with the following command:

kubectl create namespace securecodebox-system

Once the command is successfully executed, it’s possible to install secureCodeBox within the newly created namespace named securecodebox-system:

helm --namespace securecodebox-system upgrade --install securecodebox-operator secureCodeBox/operator

All of those commands can be observed on the following screenshot:

Starting minikube and deploying secureCodeBox

At this point, secureCodeBox Operator is deployed and ready for managing scans!

You can validate if pods are properly running by executing kubectl get pods -n securecodebox-system as presented below.

SecureCodeBox Pods Running in K8s

Running scans with secureCodeBox

SecureCodeBox integrates a number of popular scanners for various purposes. At the time of writing this article, there were more than 20 scanners integrations described in the official documentation, including but not limited to:

  • Static Application Security Testing (SAST) e.g. Semgrep
  • Dynamic Application Security Testing (DAST) e.g. ZAP, Nikto, Nuclei
  • Software Composition Analysis (SCA) e.g. Trivy for container scanning

Furthermore, there are various popular tools integrated such as nmap for network scans, Gitleaks for secrets detections, and much more.

SecureCodeBox Scanners Integrations

Each new scanner has to be firstly installed and configured. In this section, I’m presenting the configuration of Semgrep, which I personally really like and always recommend, especially when beginning your journey with Static Application Security Testing. If you’re a beginner with SAST, I can recommend to take a look at the following article:

Steps for installing the scanner and executing scans are similar for other scanners, but there might be slight differences in terms of configuring the triggered scan.

Since scanners in secureCodeBox are represented by ScanTypes, which is a CustomResourceDefinition in Kubernetes, they have to be installed before running a scan. Semgrep can be easily installed into secureCodeBox with the following Helm command:

helm upgrade --install semgrep secureCodeBox/semgrep -n securecodebox-system

For the purposes of this article, I used the same Kubernetes namespace that I used for the secureCodeBox operator. Potentially, you could separate scanners into a different namespace if you find it more convenient in terms of management.

Installing Semgrep Scanner

When the Semgrep ScanType is installed, we can configure the scanner for a chosen repository. The example Semgrep configuration which is available in the official documentation is presented below. You can observe that the configuration is actually a YAML document describing Scan — a custom object used by secureCodeBox in K8s.

apiVersion: "execution.securecodebox.io/v1"
kind: Scan
metadata:
name: "semgrep-vulnerable-flask-app"
spec:
# Specify a Kubernetes volume that will be shared between the scanner and the initContainer
volumes:
- name: repository
emptyDir: {}
# Mount the volume in the scan container
volumeMounts:
- mountPath: "/repo/"
name: repository
# Specify an init container to clone the repository
initContainers:
- name: "provision-git"
# Use an image that includes git
image: bitnami/git
# Mount the same volume we also use in the main container
volumeMounts:
- mountPath: "/repo/"
name: repository
# Specify the clone command and clone into the volume, mounted at /repo/
command:
- git
- clone
- "https://github.com/we45/Vulnerable-Flask-App"
- /repo/flask-app
# Parameterize the semgrep scan itself
scanType: "semgrep"
parameters:
- "-c"
- "p/ci"
- "/repo/flask-app"

In the above configuration, you can observe that prosision-git is a container which performs git clone to download a chosen repository. In this case, the Vulnerable Flask App is cloned to perform the scan against it. Vulnerable Flask App is an intenionally vulnerable web application created with Python Flask framework. Of course, changing the command parameter allows to clone any chosen repository by customising git arguments.

In the example, the repository is cloned into /repo/flask-app directory, which is also a Kubernetes volume shared between provision-git and semgrep containers. Once the repository is cloned, Semgrep starts the scan with arguments configured within parameters. These arguments, especially in terms of used rules, can be adjusted. Semgrep rules are publicly available and can be found in the rules registry.

Let’s save the YAML document as semgrep-vulnerable-flask-app.yaml and initiate the scan with the following kubectl command:

kubectl apply -f semgrep-vulnerable-flask-app.yaml -n securecodebox-system

The output of the command can be observed below:

Running Semgrep Scan Against Vulnerable Flask App

Furthermore, you can notice that I checked the scan status with the kubectl get scan command and the scan was in Scanning state. As secureCodeBox uses K8s objects to represent scans, they can be accessed in a similar way to other K8s objects!

After a few moments, the same get command can be executed again to validate if the scan finished succesfully.

As presented above, the scan was finished which is represented by Done state. Furthermore, the scanner identified 1 finding!

Accessing Findings Details

With the default configuration, findings are not saved in any robust vulnerability database. However, the scanner output can be accessed using kubectl describe command:

kubectl describe scan semgrep-vulnerable-flask-app -n securecodebox-system

In the kubectl output, we can observe the following content:

Kubectl Describe Executed on Semgrep Scan

In the screenshot above, we can see that 1 finding was identified, which we already knew from the previous log. However, there is also a Finding Download Link, which can be used to download the report. I accessed the URL, which points to the service within Kubernetes, and received the Semgrep report in JSON format as a response. Now, let’s take a look at the report:

{
...
"results": [
{
"check_id": "python.jwt.security.jwt-hardcode.jwt-python-hardcoded-secret",
"end": {
"col": 193,
"line": 184,
"offset": 6227
},
"extra": {
"engine_kind": "OSS",
"fingerprint": "221138ec7d837ea33e1e3346821e6bf50d3f21bf8600de705b7831ef2fe9139023f1f58202a21034ac06a54a67236bd9a41624ac7960e173627cb6298a92c5c6_0",
"is_ignored": false,
"lines": " auth_token = jwt.encode({'user': username, 'exp': get_exp_date(), 'nbf': datetime.datetime.utcnow(), 'iss': 'we45', 'iat': datetime.datetime.utcnow()}, app.config['SECRET_KEY_HMAC'], algorithm='HS256')",
"message": "Hardcoded JWT secret or private key is used. This is a Insufficiently Protected Credentials weakness: https://cwe.mitre.org/data/definitions/522.html Consider using an appropriate security mechanism to protect the credentials (e.g. keeping secrets in environment variables)",
"metadata": {
"category": "security",
"confidence": "HIGH",
"cwe": [
"CWE-522: Insufficiently Protected Credentials"
],
"cwe2021-top25": true,
"impact": "MEDIUM",
"license": "Commons Clause License Condition v1.0[LGPL-2.1-only]",
"likelihood": "HIGH",
"owasp": [
"A02:2017 - Broken Authentication",
"A04:2021 - Insecure Design"
],
"references": [
"https://semgrep.dev/blog/2020/hardcoded-secrets-unverified-tokens-and-other-common-jwt-mistakes/"
],
"semgrep.dev": {
"rule": {
"origin": "community",
"rule_id": "X5U8P5",
"url": "https://semgrep.dev/playground/r/l4T4vPA/python.jwt.security.jwt-hardcode.jwt-python-hardcoded-secret",
"version_id": "l4T4vPA"
}
},
...
}

In the report above, we can see that the rule python.jwt.security.jwt-hardcode.jwt-python-hardcoded-secret identified a hardcoded secret within the repository. Let’s analyse the report to understand the finding!

The issue is located exactly on line 184 and is related to the creation of a JWT token. As a secret for the token, a value stored in app.config[‘SECRET_KEY_HMAC’] variable is used. However, we don’t really know if this value is hardcoded or taken from environmental variables, etc. Therefore, let’s search where this secret might be set. After a quick search, we can find the variable definition and… the finding is a true positive!


...

app.config['SECRET_KEY_HMAC'] = 'secret'
app.config['SECRET_KEY_HMAC_2'] = 'am0r3C0mpl3xK3y'
app.secret_key = 'F12Zr47j\3yX R~X@H!jmM]Lwf/,?KT'

...


if auth_user:
auth_token = jwt.encode({'user': username, 'exp': get_exp_date(), 'nbf': datetime.datetime.utcnow(), 'iss': 'we45', 'iat': datetime.datetime.utcnow()}, app.config['SECRET_KEY_HMAC'], algorithm='HS256')
resp = Response(json.dumps({'Authenticated': True, "User": username}))
#resp.set_cookie('SESSIONID', auth_token)
resp.headers['Authorization'] = "{0}".format(auth_token)
resp.status_code = 200
resp.mimetype = 'application/json'
return resp

...

Indeed, we identified a vulnerability, but the process of accessing the report was not very efficient, especially when reading it in JSON format…

Can we improve our User Experience and make the vulnerability management more effective?

Yes, it’s possible to use DefectDojo as a vulnerability management platform integrated with secureCodeBox. This can enhance the process by providing a more user-friendly interface and efficient management of vulnerabilities.

Propagating Findings to DefectDojo

To store findings in a persistent way SecureCodeBox allows to propagate findings to various services such as:

Saving findings in those services allows to persist, analyse and effectively introduce findings into vulnerability management program. If you’d like to learn more about DefectDojo in context of vulnerability management solution, you can take a look at my recent article:

DefectDojo integration is explained in the secureCodeBox official documentation.

Summary

In this article, I presented the architecture of secureCodeBox, its available scanners, example configurations, and potential use cases. In my opinion, secureCodeBox is a very promising solution for continuous security testing and one of the few open-source projects of its kind. It provides the ability to execute scans within Kubernetes, which might be a very efficient approach if you don’t want to use your current CI/CD solution for heavy-lifting scans or looking to separate CI/CD from scans. The solution offers a number of open-source scanner integrations that can cover most, if not all, aspects of continuous security testing. Furthermore, it can be used as an all-in-one scanner to perform regular automated security assessments against your code repositories and deployed applications.

Used as a standalone scanner, secureCodeBox is pretty straightforward to configure. However, to fully utilize its strength, an effective solution would be to integrate it into CI/CD to trigger scans based on code repository-related events. Furthermore, secureCodeBox could provide reports directly to developers in CI or a dedicated dashboard, enabling developers to fix identified vulnerabilities before merging the code into the main branch.

To summarize, if you’re searching for an all-in-one open-source scanner and you’re not afraid of Kubernetes and customizing scans using YAML files, I think it’s one of the best and most underrated open-source projects available for continuous security testing.

If you’re looking for more Application Security, DevSecOps and related technical articles, just let me know what type of content you’re interested in and Follow me to get notified about new articles as soon as they’re released! 🚀🚀🚀

You can also visit my LinkedIn or Twitter profiles, if you’re keen on speaking about technical stuff! 💬

--

--

Writer for

Software Engineer and Security Researcher, writing about application security in SDLC and DevSecOps - https://devsec-blog.com 🔐