AppSec Project - Chapter 4, SAST Tools and Containerization

b1d0wsb1d0ws
7 min read

Introduction

Hello! Today, we’ll explore testing various SAST tools to evaluate their effectiveness in helping us secure our application.

Additionally, we’ll containerize our app and make final adjustments to bring the project to completion. Our branch for this article will be sast.


SAST Tools

If you’re not familiar with SAST (Static Application Security Testing) tools, they are essential in the realm of application security (AppSec). These tools automate code review, helping to identify potential vulnerabilities.

However, it’s important to note that no tool can replace manual analysis. SAST tools may produce false positives and often miss issues like business logic vulnerabilities.

Semgrep

Semgrep is arguably one of the most well-known tools for SAST analysis, so we’ll start with it.

We’ll be testing our project on the main branch, meaning all the vulnerabilities we identified in the first two chapters will still be present in the code for analysis!

Running it is very straightforward. Simply install it using pip, authenticate with Git, and execute the tool.

python3 -m pip install semgrep

semgrep login

semgrep ci

The first finding revealed an SQL Injection vulnerability.

The second identified an SSRF issue.

It also detected CSRF vulnerabilities.

Finally, it flagged an SSTI flaw.

Here’s a summary of what semgrep found compared to all vulnerabilities:

  • Lack of Authentication

  • Arbitrary File Upload and Path Traversal

  • XSS

  • CSRF ✅

  • Weak Password Reset Token Generation

  • IDOR

  • Privilege Escalation

  • SQL Injection ✅

  • SSTI ✅

  • SSRF ✅

It also flagged the hardcoded secret key we improved in the last chapter.

And highlighted other issues, such as vulnerabilities related to json.loads() and a "missing-integrity" warning. However, these were not applicable in this context.

When running the tool on the "improvements" branch, it still identified SSRF and CSRF vulnerabilities. This is because we didn’t fix the specific lines of code where the vulnerabilities were flagged. Instead, we implemented protections somewhere else in the code. This is a case of false positive.

Bandit

Bandit is another popular SAST tool, specifically focused on Python. I ran it on the project, and it identified SQL Injection and the hardcoded secret key.

An additional finding was the weak password reset token generation. It flagged the use of a pseudo-random number generator, which is the root cause of the issue, effectively pointing to the vulnerability.

Running Bandit is straightforward as well:

pipx install bandit
bandit -r . -o ../bandit_report

You can choose to output the results in a text file or generate a report in HTML format.

bandit -r . -o bandit_report.txt
bandit -r . --format html -o bandit_report.html

The last tool we tested was Bearer, and the results were disappointing because no issues were found!

This is how to download and execute it:

curl -sfL https://raw.githubusercontent.com/Bearer/bearer/main/contrib/install.sh | sh
./bin/bearer
mv bearer /usr/bin/bearer
sudo mv bearer /usr/bin/bearer
bearer
bearer scan appsec-project

The standout feature of this tool is that it flagged data types, such as Personally Identifiable Information (PII). I didn't investigate this further, but it could be helpful in identifying potential issues.

GitHub Actions (CI/CD)

Typically, these SAST tools are integrated into a Continuous Integration and Continuous Delivery (CI/CD) pipeline to speed up the analysis process.

To implement this, we set up a GitHub Action to run Semgrep every time code is pushed to the "sast" branch of our repository. This will generate a SARIF artifact that can be reviewed later.

To accomplish this, we created a file called semgrep.yaml inside the .github/workflows directory.

name: Semgrep Full Scan

on:
  push:
    branches:
      - sast

jobs:

  semgrep-full:
      runs-on: ubuntu-latest
      container:
        image: returntocorp/semgrep

      steps:

        # step 1
        - name: clone application source code
          uses: actions/checkout@v4

        # step 2
        - name: full scan
          run: |
            semgrep \
              --sarif --output report.sarif \
              --metrics=off \
              --config="p/default"

        # step 3
        - name: save report as pipeline artifact
          uses: actions/upload-artifact@v4
          with:
            name: report.sarif
            path: report.sarif

        # step 4
        - name: Download report
          uses: actions/download-artifact@v4
          with: 
            name: report.sarif

I won’t go into the details of this file, but essentially, it runs the Semgrep command on an Ubuntu machine and saves the results as an artifact called report.sarif.


Containerization

For our final project action, we’ll containerize the application. While this isn't directly related to security, containerization comes with best practices that enhance security. It also ties closely to CI/CD, which is often a key responsibility for AppSec or DevSecOps professionals.

The first thing I learned here is the importance of creating a virtual environment before generating the requirements.txt file. If you generate it outside of an environment, it will include all the libraries installed on your machine, even those not used in the project.

The problem with using a virtual environment only after developing everything is that you'll have to reinstall the libraries you've used.

pip install virtualenv
python3 -m venv .
source bin/activate
# reinstall the libraries if you are only using virtualenv now
pip freeze > requirements.txt

Now, to build our Docker image, we need to create a Dockerfile with the following configuration:

FROM python:3-alpine3.15
WORKDIR /app
COPY . /app
RUN pip install -r requirements.txt
EXPOSE 5000
CMD python ./main.py

This configuration essentially sets the main directory inside the container to /app, installs the libraries listed in requirements.txt using pip, exposes port 5000, and runs our main file, main.py.

Now we can build the Docker image, test it, and push it to our hub using the following commands:

# Building docker
docker build -t bido/appsec-project:latest .

# Testing, this will expose port 5000 on your machine as well
docker container run -d -p 5000:5000 bido/appsec-project:latest

# Check if container is running
docker container ls

# You have have docker hub and docker login setup.

# Pushing to docker hub
docker push bido/appsec-project:latest

One important detail is that we need to change the IP to 0.0.0.0 to make the application accessible to the network, instead of using 127.0.0.1, which would restrict the port to the container’s scope.

if __name__ == '__main__':
    # app.run()
    app.run(host="0.0.0.0")

Now, we can use the application anywhere by simply pulling the container and running it with the command we used before.

docker pull bido/appsec-project
💡
We’ve added a Docker image to download the vulnerable version that starts this project. The image is bido/appsec-project:vulnerable.

Final Adjustments

One thing that our SAST tools didn’t detect was the secret key in the .env file.

We’ll remove this file in the next commit by adding it to the .gitignore file. To remove the .env file from the GitHub repository without deleting it from the local machine, execute the following commands:

git rm --cached .env
echo ".env" >> .gitignore

Additionally, our commit history will include the .env file and the hardcoded secret key, as seen in commit 23089d278000e480a5683fa22771cb00a5e0b4ea.

We should remove this commit from the history, but we will keep it here for educational purposes.


Conclusion

In this article, we explored the process of enhancing the security of a web application using various Static Application Security Testing (SAST) tools, such as Semgrep, Bandit, and Bearer.

Each tool provided valuable insights, highlighting vulnerabilities such as SQL Injection, SSRF, CSRF, and weak password reset token generation, while also pointing out potential issues like hardcoded secrets.

While SAST tools can automate vulnerability detection, they still require manual analysis to ensure no critical vulnerabilities are missed.

We also took steps to improve our development workflow by integrating Semgrep into a GitHub Action, enabling continuous scanning with every commit. Furthermore, we containerized the application, following best practices to enhance security in a CI/CD pipeline.

That concludes our project! I hope you found it helpful. There’s always room for improvement, so if you think you can contribute, feel free to fork the repository or submit a pull request to help make it even better!

Thank you all, see ya =)

0
Subscribe to my newsletter

Read articles from b1d0ws directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

b1d0ws
b1d0ws