CI/CD pipeline security analyzer — scans GitHub Actions, GitLab CI, and Azure DevOps configs for attack vectors
Project description
FlowSec
A Python security tool that scans CI/CD pipeline configurations for attack vectors across GitHub Actions, GitLab CI, and Azure DevOps. Every finding maps to a MITRE ATT&CK technique and OWASP CICD Top 10 category.
The pipeline is the attack surface. FlowSec treats it that way.
What it catches
| ID | Rule | Severity | MITRE | OWASP |
|---|---|---|---|---|
| FS001 | Hardcoded Secret — Plaintext Credential in Workflow | CRITICAL | T1552.001 | CICD-SEC-6 |
| FS002 | Unpinned Action — Supply Chain Attack Vector | CRITICAL | T1195.001 | CICD-SEC-3 |
| FS003 | Excessive Permissions — Overprivileged Workflow Token | HIGH | T1078 | CICD-SEC-5 |
| FS004 | Missing OIDC — Long-Lived Cloud Credential in Use | HIGH | T1552.004 | CICD-SEC-6 |
| FS005 | Pull Request Target — Secrets Exposed to Fork Code | CRITICAL | T1611 | CICD-SEC-4 |
| FS006 | Missing Timeout — Job Runs Up to 6 Hours Unchecked | LOW | T1499 | CICD-SEC-10 |
| FS007 | Self-Hosted Runner — Persistent Environment Risk | HIGH | T1053 | CICD-SEC-7 |
| FS008 | Missing Artifact Signing — No Tamper Protection | MEDIUM | T1553 | CICD-SEC-8 |
| FS009 | Unpinned Dependency — Package Installed Without Version Lock | HIGH | T1195.002 | CICD-SEC-3 |
| FS010 | Secret in Run Command — Plaintext Credential in Shell Step | CRITICAL | T1552.001 | CICD-SEC-6 |
| FS011 | Missing Branch Protection — Direct Push to Default Branch Possible | HIGH | T1098 | CICD-SEC-1 |
| FS012 | Missing Environment Protection — Deploy Job Has No Approval Gate | HIGH | T1078 | CICD-SEC-5 |
| FS013 | Workflow Dispatch Injection — Unvalidated Input in Shell Command | CRITICAL | T1059 | CICD-SEC-9 |
Platforms supported
| Platform | How to scan |
|---|---|
| GitHub Actions | flowsec scan --repo owner/repo or --file workflow.yml |
| GitLab CI | flowsec scan --gitlab .gitlab-ci.yml |
| Azure DevOps | flowsec scan --azure azure-pipelines.yml |
Real findings on a real repo
Scanned VanshBhardwaj1945/cloud-resume-challenge-azure — 13 findings across 2 workflow files:
[CRITICAL] FS002 - Unpinned Action — Supply Chain Attack Vector
File: .github/workflows/backend.main.yaml
Action 'actions/checkout@v4' is not pinned to a commit hash
[HIGH] FS003 - Excessive Permissions — Overprivileged Workflow Token
File: .github/workflows/backend.main.yaml
Pipeline permissions set to 'None' — GitHub defaults apply
[HIGH] FS004 - Missing OIDC — Long-Lived Cloud Credential in Use
File: .github/workflows/backend.main.yaml
Cloud provider action present but no id-token: write permission
[LOW] FS006 - Missing Timeout — Job Runs Up to 6 Hours Unchecked
File: .github/workflows/backend.main.yaml
Job 'build-and-deploy' has no timeout — GitHub default is 6 hours
Stack
| Layer | Tools |
|---|---|
| Language | Python 3.11 |
| GitHub Connection | PyGithub |
| YAML Parsing | PyYAML with custom line-tracking loader |
| Terminal Output | rich |
| HTML Reports | Jinja2 — interactive filtering, expandable findings, PDF export |
| AI Narratives | Anthropic Claude API with local caching |
| Linting | ruff, mypy, bandit |
| Packaging | hatch, pyproject.toml |
| Containerization | Docker |
Quick Start
Click the Codespaces button above to run FlowSec in your browser with zero setup. Or run locally:
git clone https://github.com/VanshBhardwaj1945/FlowSec.git
cd FlowSec
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env
# Add your GITHUB_TOKEN to .env
flowsec scan --repo owner/repo
flowsec scan --file .github/workflows/ci.yml
flowsec scan --gitlab .gitlab-ci.yml
flowsec scan --azure azure-pipelines.yml
flowsec scan --repo owner/repo --ai --output report.html
Use as a Pipeline Gate
Add FlowSec to your own GitHub Actions workflow to automatically block PRs that introduce security misconfigurations:
name: FlowSec Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install FlowSec
run: pip install flowsec
- name: Run FlowSec
run: flowsec scan --file .github/workflows/ --fail-on critical
--fail-on critical exits with code 1 if any CRITICAL findings are found, failing the pipeline and blocking the PR. Supports critical, high, medium, and low thresholds.
Status
| Component | Status |
|---|---|
| Rule engine — BaseRule, Finding, Severity | Complete |
| YAML parser with line number tracking | Complete |
| 13 security rules FS001-FS013 | Complete |
| MITRE ATT&CK + OWASP CICD Top 10 mapping | Complete |
| Platform-aware rule engine | Complete |
| GitHub Actions scanner — API and local file | Complete |
| GitLab CI scanner | Complete |
| Azure DevOps scanner | Complete |
| CLI — --repo, --file, --gitlab, --azure, --ai, --output, --fail-on | Complete |
| Rich terminal output with risk score | Complete |
| HTML report with filtering, PDF export | Complete |
| AI attack narratives with local caching | Complete |
| Line number tracking | Complete |
| Pipeline gate flag --fail-on | Complete |
| GitHub Codespace config | Complete |
| PyPI publish | Pending |
| Web app — FastAPI + frontend | Pending |
| Web app — Azure Container Apps deployment | Pending |
Roadmap
Phase 1 — Core CLI
PyPI publish so anyone can pip install flowsec.
Phase 2 — Web App FastAPI backend, frontend for repo input and file upload, deployed to Azure Container Apps via GitHub Actions. Anyone can scan a pipeline from a browser without installing anything.
Phase 3 — Expansion Jenkins support, AWS CodePipeline, 20+ rule library, rate limiting.
About this project
Built as a security engineering portfolio project. The goal was to build an actual security tool — not run existing ones — and document every decision along the way.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file flowsec-0.1.0.tar.gz.
File metadata
- Download URL: flowsec-0.1.0.tar.gz
- Upload date:
- Size: 22.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
959f20c07cf186411ff2b575f2d6636081a9ab7a4e0d061e286763cb11f08a38
|
|
| MD5 |
2430a000b59bb2d6f96b67aed3034eb7
|
|
| BLAKE2b-256 |
f630ca7ad38cc94ef7ac86dbe29b59a68d035bce1034016e8359bf531af1552a
|
Provenance
The following attestation bundles were made for flowsec-0.1.0.tar.gz:
Publisher:
publish.yml on VanshBhardwaj1945/FlowSec
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flowsec-0.1.0.tar.gz -
Subject digest:
959f20c07cf186411ff2b575f2d6636081a9ab7a4e0d061e286763cb11f08a38 - Sigstore transparency entry: 1406096508
- Sigstore integration time:
-
Permalink:
VanshBhardwaj1945/FlowSec@94114de984157ae5d3498d06acf3ba115c2dc03a -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/VanshBhardwaj1945
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@94114de984157ae5d3498d06acf3ba115c2dc03a -
Trigger Event:
push
-
Statement type:
File details
Details for the file flowsec-0.1.0-py3-none-any.whl.
File metadata
- Download URL: flowsec-0.1.0-py3-none-any.whl
- Upload date:
- Size: 24.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90f36f7f47443123ed8911d7b3fbed3e6cf04bac7af7385d55daf374c909dae7
|
|
| MD5 |
2dfeea042be2bdd0bca6e209c19469d6
|
|
| BLAKE2b-256 |
ef3100136b9354726d9078f65e731cecbc0cc2f1c29fd197bb283c9567a75252
|
Provenance
The following attestation bundles were made for flowsec-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on VanshBhardwaj1945/FlowSec
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flowsec-0.1.0-py3-none-any.whl -
Subject digest:
90f36f7f47443123ed8911d7b3fbed3e6cf04bac7af7385d55daf374c909dae7 - Sigstore transparency entry: 1406096515
- Sigstore integration time:
-
Permalink:
VanshBhardwaj1945/FlowSec@94114de984157ae5d3498d06acf3ba115c2dc03a -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/VanshBhardwaj1945
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@94114de984157ae5d3498d06acf3ba115c2dc03a -
Trigger Event:
push
-
Statement type: