<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Abel Fernando PACOMPIA ORTIZ</title>
    <description>The latest articles on DEV Community by Abel Fernando PACOMPIA ORTIZ (@abel_fernandopacompiaor).</description>
    <link>https://dev.to/abel_fernandopacompiaor</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4004729%2Fdbff5f55-6b75-4cd3-9755-b491f268dd5c.png</url>
      <title>DEV Community: Abel Fernando PACOMPIA ORTIZ</title>
      <link>https://dev.to/abel_fernandopacompiaor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abel_fernandopacompiaor"/>
    <language>en</language>
    <item>
      <title>Applying Pytest and Requests for Real-World API Testing in a FastAPI Application</title>
      <dc:creator>Abel Fernando PACOMPIA ORTIZ</dc:creator>
      <pubDate>Sat, 27 Jun 2026 07:41:53 +0000</pubDate>
      <link>https://dev.to/abel_fernandopacompiaor/applying-pytest-and-requests-for-real-world-api-testing-in-a-fastapi-application-3oj9</link>
      <guid>https://dev.to/abel_fernandopacompiaor/applying-pytest-and-requests-for-real-world-api-testing-in-a-fastapi-application-3oj9</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;API testing is an essential practice for validating backend applications before they are deployed. In this project, I built a small FastAPI application and tested its endpoints using Pytest and FastAPI TestClient. The goal is to show a practical and academic example of how automated API tests can improve reliability.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is API Testing?
&lt;/h2&gt;

&lt;p&gt;API testing verifies the behavior of application endpoints. Instead of checking visual elements, API tests send HTTP requests and validate status codes, response bodies, data formats, and error handling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why API Testing is Important
&lt;/h2&gt;

&lt;p&gt;Modern applications often depend on APIs to connect frontends, services, databases, and external systems. If an API endpoint fails, many parts of the system can be affected. Automated API tests help detect problems early and provide confidence when making changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Testing Frameworks Comparative
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Framework&lt;/th&gt;
&lt;th&gt;Language / Ecosystem&lt;/th&gt;
&lt;th&gt;Best use case&lt;/th&gt;
&lt;th&gt;Automation support&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pytest + Requests / TestClient&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;Developer-friendly automated API tests&lt;/td&gt;
&lt;td&gt;Excellent with CI/CD tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Postman + Newman&lt;/td&gt;
&lt;td&gt;JavaScript / CLI ecosystem&lt;/td&gt;
&lt;td&gt;Manual and automated API collections&lt;/td&gt;
&lt;td&gt;Good for pipeline execution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rest Assured&lt;/td&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;API testing in Java projects&lt;/td&gt;
&lt;td&gt;Strong with Maven, Gradle, and CI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Karate DSL&lt;/td&gt;
&lt;td&gt;Java / DSL&lt;/td&gt;
&lt;td&gt;BDD-style API tests with readable scenarios&lt;/td&gt;
&lt;td&gt;Good CI/CD integration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why I Chose Pytest
&lt;/h2&gt;

&lt;p&gt;I chose Pytest because it is simple, readable, and widely used in Python projects. It allows developers to write test functions with plain assertions, and it integrates easily with FastAPI through TestClient.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo API with FastAPI
&lt;/h2&gt;

&lt;p&gt;The demo API provides endpoints for a welcome message, health check, listing users, retrieving a user by id, and creating a new user in memory.&lt;/p&gt;

&lt;p&gt;Example from &lt;code&gt;app/main.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/users/{user_id}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return one user by id or a clear 404 error.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;

    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_404_NOT_FOUND&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User with id &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; was not found.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing Real-World API Test Cases
&lt;/h2&gt;

&lt;p&gt;The test suite checks successful responses, response content, list structures, user lookup, error handling, and validation failures.&lt;/p&gt;

&lt;p&gt;Example from &lt;code&gt;tests/test_api.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_health_check_returns_ok&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Validates that the health endpoint reports the API as available.
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/health&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running the Tests Locally
&lt;/h2&gt;

&lt;p&gt;To install dependencies and run the tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;requirements.txt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Automating API Tests with GitHub Actions
&lt;/h2&gt;

&lt;p&gt;GitHub Actions can run the test suite automatically when code is pushed or when a pull request is opened.&lt;/p&gt;

&lt;p&gt;Example from &lt;code&gt;.github/workflows/api-tests.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;API Tests with Pytest&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;api-tests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;The project includes seven API tests that validate the main behavior of the demo application. These tests can be executed locally with Pytest and automatically in GitHub Actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Pytest is a strong option for API testing in Python because it is readable, flexible, and easy to automate. Combined with FastAPI and GitHub Actions, it supports a simple but effective workflow for validating backend behavior before deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Repository Link
&lt;/h2&gt;

&lt;p&gt;GitHub repository: &lt;a href="https://github.com/Abel-GG-777/api-testing-pytest-demo.git" rel="noopener noreferrer"&gt;https://github.com/Abel-GG-777/api-testing-pytest-demo.git&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>testing</category>
      <category>fastapi</category>
      <category>pytest</category>
    </item>
    <item>
      <title>Applying Checkov SAST to Detect Security Issues in Terraform Infrastructure as Code</title>
      <dc:creator>Abel Fernando PACOMPIA ORTIZ</dc:creator>
      <pubDate>Sat, 27 Jun 2026 05:47:57 +0000</pubDate>
      <link>https://dev.to/abel_fernandopacompiaor/applying-checkov-sast-to-detect-security-issues-in-terraform-infrastructure-as-code-14gp</link>
      <guid>https://dev.to/abel_fernandopacompiaor/applying-checkov-sast-to-detect-security-issues-in-terraform-infrastructure-as-code-14gp</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Security issues in cloud infrastructure often start as small configuration mistakes. A public network rule, a missing encryption setting, or an overly permissive policy can create serious risk when infrastructure is deployed.&lt;/p&gt;

&lt;p&gt;This demo project shows how to use Checkov as a Static Application Security Testing tool for Terraform Infrastructure as Code. The goal is academic and practical: detect insecure Terraform configuration before deploying anything to the cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Infrastructure as Code?
&lt;/h2&gt;

&lt;p&gt;Infrastructure as Code, or IaC, is the practice of defining infrastructure using code. Instead of manually creating cloud resources through a web console, teams describe resources in files that can be versioned, reviewed, tested, and automated.&lt;/p&gt;

&lt;p&gt;Terraform is one of the most popular IaC tools. It allows teams to define providers, networks, storage, compute resources, permissions, and other infrastructure components using declarative configuration files.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is SAST for IaC?
&lt;/h2&gt;

&lt;p&gt;Static Application Security Testing normally means analyzing source code without running it. For IaC, the same idea applies to infrastructure definitions. A scanner can inspect Terraform files and identify risky patterns before the infrastructure is created.&lt;/p&gt;

&lt;p&gt;This is useful because security feedback arrives earlier in the development lifecycle. Developers and DevOps teams can fix misconfigurations before they become real cloud exposure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Checkov?
&lt;/h2&gt;

&lt;p&gt;Checkov is a static analysis tool designed for Infrastructure as Code. It supports Terraform and can detect issues such as public access, missing encryption, weak network rules, and insecure cloud service configuration.&lt;/p&gt;

&lt;p&gt;For this project, Checkov is a good fit because it is simple to run locally, easy to integrate into GitHub Actions, and focused on IaC security scanning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vulnerable Terraform demo
&lt;/h2&gt;

&lt;p&gt;The vulnerable Terraform file defines an AWS provider, a security group, and an S3 bucket. The file is intentionally insecure for demonstration purposes only.&lt;/p&gt;

&lt;p&gt;One important issue is SSH exposed to the entire internet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Insecure SSH access from anywhere"&lt;/span&gt;
  &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
  &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
  &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SSH open to &lt;code&gt;0.0.0.0/0&lt;/code&gt; is insecure because any public IP address can attempt to connect. This increases the attack surface and can expose servers to brute-force attacks, credential attacks, and unauthorized access attempts.&lt;/p&gt;

&lt;p&gt;The vulnerable version also includes fully open outbound traffic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;egress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Overly permissive outbound access"&lt;/span&gt;
  &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"-1"&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fully open egress is too permissive because it allows outbound traffic to any destination, using any protocol and port. In a real environment, this can make data exfiltration or unauthorized external communication easier.&lt;/p&gt;

&lt;p&gt;The S3 bucket is also basic and does not define extra protections such as public access blocking or explicit encryption:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket"&lt;/span&gt; &lt;span class="s2"&gt;"vulnerable_bucket"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"checkov-sast-demo-vulnerable-bucket"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running Checkov locally
&lt;/h2&gt;

&lt;p&gt;Checkov can be installed and executed with Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;checkov&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;checkov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--framework&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--skip-path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;venv&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;checkov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--framework&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--skip-path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;venv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-o&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cli&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;checkov-report.txt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-d .&lt;/code&gt; option tells Checkov to scan the current directory. The &lt;code&gt;-o cli&lt;/code&gt; option prints the report in command-line format, and the final command stores the output in a text report.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explaining findings
&lt;/h2&gt;

&lt;p&gt;Checkov analyzes the Terraform files and compares them with security policies. In this demo, it should identify risky patterns such as public SSH exposure, missing S3 security controls, and overly permissive network configuration.&lt;/p&gt;

&lt;p&gt;These findings matter because infrastructure misconfigurations can become real vulnerabilities after deployment. Detecting them statically helps reduce risk before cloud resources exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secure Terraform version
&lt;/h2&gt;

&lt;p&gt;The secure Terraform version restricts SSH to a trusted example IP address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"SSH access from a trusted example IP"&lt;/span&gt;
  &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
  &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
  &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"203.0.113.10/32"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;203.0.113.10/32&lt;/code&gt; address is documentation-only example IP space. In a real project, this should be replaced with an approved corporate VPN, bastion host, or administrative IP range.&lt;/p&gt;

&lt;p&gt;The secure file also restricts egress to HTTPS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;egress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTPS outbound access only"&lt;/span&gt;
  &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;
  &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;
  &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For S3, the secure version enables public access blocking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_public_access_block"&lt;/span&gt; &lt;span class="s2"&gt;"secure_bucket_public_access"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secure_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;block_public_acls&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;block_public_policy&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;ignore_public_acls&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;restrict_public_buckets&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Blocking public access helps prevent accidental exposure of data. This is especially important because S3 buckets are commonly used to store sensitive application, backup, log, or user data.&lt;/p&gt;

&lt;p&gt;The secure version also enables server-side encryption:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_server_side_encryption_configuration"&lt;/span&gt; &lt;span class="s2"&gt;"secure_bucket_encryption"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secure_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;rule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;apply_server_side_encryption_by_default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;sse_algorithm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AES256"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;S3 encryption is a good practice because it protects stored objects at rest. Even when access controls are also required, encryption adds another layer of defense.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Actions automation
&lt;/h2&gt;

&lt;p&gt;The project includes a GitHub Actions workflow that runs Checkov automatically on pushes and pull requests to the &lt;code&gt;main&lt;/code&gt; branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkov IaC SAST Scan&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;checkov&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Checkov&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Checkov Terraform scan&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bridgecrewio/checkov-action@master&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
          &lt;span class="na"&gt;framework&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform&lt;/span&gt;
          &lt;span class="na"&gt;output_format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cli&lt;/span&gt;
          &lt;span class="na"&gt;soft_fail&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Integrating Checkov into GitHub Actions improves the DevSecOps workflow because every change can be scanned automatically before it is merged. This helps teams detect insecure Terraform code during code review instead of after deployment.&lt;/p&gt;

&lt;p&gt;In this academic demo, &lt;code&gt;soft_fail: true&lt;/code&gt; is used because the repository intentionally contains vulnerable Terraform code. This setting keeps the pipeline successful while still displaying the security findings in the workflow logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This project demonstrates how Checkov can be used to detect security issues in Terraform Infrastructure as Code. The vulnerable version shows common cloud misconfigurations, while the secure version demonstrates safer alternatives.&lt;/p&gt;

&lt;p&gt;By combining local scanning with GitHub Actions automation, teams can introduce security checks early and continuously in the CI/CD process.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub repository link placeholder
&lt;/h2&gt;

&lt;p&gt;GitHub repository: &lt;a href="https://github.com/Abel-GG-777/checkov-terraform-sast-demo.git" rel="noopener noreferrer"&gt;https://github.com/Abel-GG-777/checkov-terraform-sast-demo.git&lt;/a&gt;&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>security</category>
      <category>devsecops</category>
      <category>checkov</category>
    </item>
    <item>
      <title>Applying Bandit SAST to Detect Vulnerabilities in a Python Flask Application</title>
      <dc:creator>Abel Fernando PACOMPIA ORTIZ</dc:creator>
      <pubDate>Sat, 27 Jun 2026 03:26:12 +0000</pubDate>
      <link>https://dev.to/abel_fernandopacompiaor/applying-bandit-sast-to-detect-vulnerabilities-in-a-python-flask-application-5g89</link>
      <guid>https://dev.to/abel_fernandopacompiaor/applying-bandit-sast-to-detect-vulnerabilities-in-a-python-flask-application-5g89</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Security should be part of the development workflow, not only a final checklist before deployment. One practical way to introduce security earlier is by using Static Application Security Testing tools. In this article, I demonstrate how to use Bandit to analyze a small Python Flask application that intentionally contains insecure code.&lt;/p&gt;

&lt;p&gt;GitHub repository: &lt;a href="https://github.com/Abel-GG-777/bandit-sast-python-demo" rel="noopener noreferrer"&gt;https://github.com/Abel-GG-777/bandit-sast-python-demo&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is SAST?
&lt;/h2&gt;

&lt;p&gt;Static Application Security Testing, commonly called SAST, is a security testing approach that analyzes source code without executing the application. Instead of waiting until runtime, SAST tools inspect code patterns and identify potential vulnerabilities early in the development lifecycle.&lt;/p&gt;

&lt;p&gt;SAST is especially useful in academic and professional environments because it can be automated in CI/CD pipelines and used by developers before code is merged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Bandit?
&lt;/h2&gt;

&lt;p&gt;Bandit is a SAST tool designed specifically for Python. It scans Python files and reports common security issues such as hardcoded credentials, unsafe subprocess usage, weak cryptography, and risky configuration.&lt;/p&gt;

&lt;p&gt;For this demo, Bandit is a good choice because it is lightweight, easy to install, simple to run from the command line, and easy to integrate with GitHub Actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo Vulnerable Code Explanation
&lt;/h2&gt;

&lt;p&gt;The demo application is a small Flask project in &lt;code&gt;app.py&lt;/code&gt;. It intentionally includes several insecure patterns so Bandit can detect them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A hardcoded administrator password stored directly in the source code.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;subprocess.check_output&lt;/code&gt; call using &lt;code&gt;shell=True&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;User input from a query parameter concatenated into a shell command, creating a possible command injection risk.&lt;/li&gt;
&lt;li&gt;The use of &lt;code&gt;hashlib.md5&lt;/code&gt;, a weak hashing algorithm for security-sensitive use cases.&lt;/li&gt;
&lt;li&gt;Flask running with &lt;code&gt;debug=True&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These vulnerabilities are intentionally simple so the results are easy to explain in a classroom or presentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Bandit Locally
&lt;/h2&gt;

&lt;p&gt;First, install the dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run Bandit against the repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; bandit &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To generate a text report, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; bandit &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; txt &lt;span class="nt"&gt;-o&lt;/span&gt; bandit-report.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Explaining Findings
&lt;/h2&gt;

&lt;p&gt;Bandit reports issues with identifiers, severity levels, confidence levels, file paths, and line numbers. In this project, the expected findings are related to hardcoded credentials, subprocess execution, shell usage, MD5 hashing, and debug mode.&lt;/p&gt;

&lt;p&gt;The important part of the demo is not only seeing the warnings, but understanding why each pattern is risky. For example, &lt;code&gt;shell=True&lt;/code&gt; becomes dangerous when combined with user-controlled input because the shell may interpret special characters as commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secure Code Improvements
&lt;/h2&gt;

&lt;p&gt;The corrected version is implemented in &lt;code&gt;app_secure.py&lt;/code&gt;. It applies simple improvements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The password is loaded from the &lt;code&gt;ADMIN_PASSWORD&lt;/code&gt; environment variable.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;shell=True&lt;/code&gt; is removed.&lt;/li&gt;
&lt;li&gt;The subprocess call uses a list of arguments instead of a shell command string.&lt;/li&gt;
&lt;li&gt;MD5 is replaced with SHA-256.&lt;/li&gt;
&lt;li&gt;Flask debug mode is disabled.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This secure version keeps the application easy to understand while showing how vulnerable patterns can be improved.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Actions Automation
&lt;/h2&gt;

&lt;p&gt;The repository includes a GitHub Actions workflow at &lt;code&gt;.github/workflows/bandit.yml&lt;/code&gt;. It runs on pushes and pull requests targeting the &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;

&lt;p&gt;The workflow checks out the repository, configures Python 3.11, installs dependencies, and runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; bandit &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This demonstrates how SAST can become part of a continuous integration process. Every push or pull request can be scanned automatically before changes are accepted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Bandit is a practical tool for introducing SAST into Python projects. It is simple to run locally, easy to automate, and useful for identifying common insecure coding patterns. This demo shows how a vulnerable Flask application can be scanned, how the findings can be explained, and how a corrected version can reduce the reported risks.&lt;/p&gt;

</description>
      <category>python</category>
      <category>flask</category>
      <category>security</category>
      <category>bandit</category>
    </item>
    <item>
      <title>Applying Bandit SAST to Detect Vulnerabilities in a Python Flask Application</title>
      <dc:creator>Abel Fernando PACOMPIA ORTIZ</dc:creator>
      <pubDate>Sat, 27 Jun 2026 03:26:12 +0000</pubDate>
      <link>https://dev.to/abel_fernandopacompiaor/applying-bandit-sast-to-detect-vulnerabilities-in-a-python-flask-application-542d</link>
      <guid>https://dev.to/abel_fernandopacompiaor/applying-bandit-sast-to-detect-vulnerabilities-in-a-python-flask-application-542d</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Security should be part of the development workflow, not only a final checklist before deployment. One practical way to introduce security earlier is by using Static Application Security Testing tools. In this article, I demonstrate how to use Bandit to analyze a small Python Flask application that intentionally contains insecure code.&lt;/p&gt;

&lt;p&gt;GitHub repository: &lt;a href="https://github.com/Abel-GG-777/bandit-sast-python-demo" rel="noopener noreferrer"&gt;https://github.com/Abel-GG-777/bandit-sast-python-demo&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is SAST?
&lt;/h2&gt;

&lt;p&gt;Static Application Security Testing, commonly called SAST, is a security testing approach that analyzes source code without executing the application. Instead of waiting until runtime, SAST tools inspect code patterns and identify potential vulnerabilities early in the development lifecycle.&lt;/p&gt;

&lt;p&gt;SAST is especially useful in academic and professional environments because it can be automated in CI/CD pipelines and used by developers before code is merged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Bandit?
&lt;/h2&gt;

&lt;p&gt;Bandit is a SAST tool designed specifically for Python. It scans Python files and reports common security issues such as hardcoded credentials, unsafe subprocess usage, weak cryptography, and risky configuration.&lt;/p&gt;

&lt;p&gt;For this demo, Bandit is a good choice because it is lightweight, easy to install, simple to run from the command line, and easy to integrate with GitHub Actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo Vulnerable Code Explanation
&lt;/h2&gt;

&lt;p&gt;The demo application is a small Flask project in &lt;code&gt;app.py&lt;/code&gt;. It intentionally includes several insecure patterns so Bandit can detect them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A hardcoded administrator password stored directly in the source code.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;subprocess.check_output&lt;/code&gt; call using &lt;code&gt;shell=True&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;User input from a query parameter concatenated into a shell command, creating a possible command injection risk.&lt;/li&gt;
&lt;li&gt;The use of &lt;code&gt;hashlib.md5&lt;/code&gt;, a weak hashing algorithm for security-sensitive use cases.&lt;/li&gt;
&lt;li&gt;Flask running with &lt;code&gt;debug=True&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These vulnerabilities are intentionally simple so the results are easy to explain in a classroom or presentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Bandit Locally
&lt;/h2&gt;

&lt;p&gt;First, install the dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run Bandit against the repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; bandit &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To generate a text report, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; bandit &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; txt &lt;span class="nt"&gt;-o&lt;/span&gt; bandit-report.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Explaining Findings
&lt;/h2&gt;

&lt;p&gt;Bandit reports issues with identifiers, severity levels, confidence levels, file paths, and line numbers. In this project, the expected findings are related to hardcoded credentials, subprocess execution, shell usage, MD5 hashing, and debug mode.&lt;/p&gt;

&lt;p&gt;The important part of the demo is not only seeing the warnings, but understanding why each pattern is risky. For example, &lt;code&gt;shell=True&lt;/code&gt; becomes dangerous when combined with user-controlled input because the shell may interpret special characters as commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Secure Code Improvements
&lt;/h2&gt;

&lt;p&gt;The corrected version is implemented in &lt;code&gt;app_secure.py&lt;/code&gt;. It applies simple improvements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The password is loaded from the &lt;code&gt;ADMIN_PASSWORD&lt;/code&gt; environment variable.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;shell=True&lt;/code&gt; is removed.&lt;/li&gt;
&lt;li&gt;The subprocess call uses a list of arguments instead of a shell command string.&lt;/li&gt;
&lt;li&gt;MD5 is replaced with SHA-256.&lt;/li&gt;
&lt;li&gt;Flask debug mode is disabled.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This secure version keeps the application easy to understand while showing how vulnerable patterns can be improved.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Actions Automation
&lt;/h2&gt;

&lt;p&gt;The repository includes a GitHub Actions workflow at &lt;code&gt;.github/workflows/bandit.yml&lt;/code&gt;. It runs on pushes and pull requests targeting the &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;

&lt;p&gt;The workflow checks out the repository, configures Python 3.11, installs dependencies, and runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; bandit &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This demonstrates how SAST can become part of a continuous integration process. Every push or pull request can be scanned automatically before changes are accepted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Bandit is a practical tool for introducing SAST into Python projects. It is simple to run locally, easy to automate, and useful for identifying common insecure coding patterns. This demo shows how a vulnerable Flask application can be scanned, how the findings can be explained, and how a corrected version can reduce the reported risks.&lt;/p&gt;

</description>
      <category>python</category>
      <category>flask</category>
      <category>security</category>
      <category>bandit</category>
    </item>
  </channel>
</rss>
