CI/CD pipeline security analyzer — scans GitHub Actions, GitLab CI, and Azure DevOps configs for attack vectors
Project description
FlowSec
A Python command-line 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 an OWASP CICD Top 10 category.
The pipeline is the attack surface. FlowSec treats it that way.
Install
Homebrew (macOS):
brew install VanshBhardwaj1945/flowsec/flowsec
PyPI:
pip install flowsec
Quick Start
# Scan a GitHub Actions repo
export GITHUB_TOKEN=your_token
flowsec scan --github --repo owner/repo
# Scan a local GitHub Actions workflow file
flowsec scan --github --file .github/workflows/ci.yml
# Scan a GitLab CI file
flowsec scan --gitlab --file .gitlab-ci.yml
# Scan an Azure DevOps pipeline file
flowsec scan --azure --file azure-pipelines.yml
# Generate an HTML report
flowsec scan --github --repo owner/repo --output report.html
# Generate AI attack narratives (requires ANTHROPIC_API_KEY)
flowsec scan --github --repo owner/repo --ai
# Fail pipeline if findings at or above threshold
flowsec scan --github --repo owner/repo --fail-on critical
# Ignore specific rules
flowsec scan --github --repo owner/repo --ignore FS006 --ignore FS011
Platforms and Tokens
| Platform | File scan | Remote scan | Token required |
|---|---|---|---|
| GitHub Actions | --github --file |
--github --repo owner/repo |
GITHUB_TOKEN (remote only) |
| GitLab CI | --gitlab --file |
--gitlab --repo namespace/project |
GITLAB_TOKEN (remote only) |
| Azure DevOps | --azure --file |
--azure --repo org/project |
AZURE_DEVOPS_TOKEN (always — Azure requires auth even for public projects) |
Set tokens in a .env file in your working directory or as environment variables. FlowSec loads .env automatically.
26 Security Rules
| 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 | GitHub Context Injection — Untrusted Event Data in Run Step | CRITICAL | T1059.004 | CICD-SEC-4 |
| 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 |
| FS014 | Mutable Container Image — Unpinned Image Tag in Pipeline | MEDIUM | T1195.001 | CICD-SEC-3 |
| FS015 | Persist Credentials — GitHub Token Remains in Git Config After Checkout | MEDIUM | T1552.001 | CICD-SEC-6 |
| FS016 | workflow_run Trigger — Privileged Execution from Untrusted Workflow | HIGH | T1059 | CICD-SEC-1 |
| FS017 | Security Scan Silenced — Failures Suppressed with continue-on-error | MEDIUM | T1562.001 | CICD-SEC-7 |
| FS018 | Secret as CLI Argument — Credential Exposed in Process List | HIGH | T1552 | CICD-SEC-6 |
| FS019 | Unverified Install Script — Remote Code Fetched and Executed Directly | HIGH | T1195.002 | CICD-SEC-3 |
| FS020 | Container Running as Root — Elevated Privilege in Pipeline | HIGH | T1611 | CICD-SEC-7 |
| FS021 | Secret in Docker Build Argument — Credential Stored in Image History | HIGH | T1552.001 | CICD-SEC-6 |
| FS022 | Broad Artifact Upload — Entire Workspace Exposed as Artifact | MEDIUM | T1560 | CICD-SEC-9 |
| FS023 | Insecure curl — SSL Verification Disabled in Pipeline | HIGH | T1071 | CICD-SEC-3 |
| FS024 | Privileged Docker Container — Full Host Access Granted in Pipeline | CRITICAL | T1611 | CICD-SEC-7 |
| FS025 | Environment Variables Printed to Logs — Secrets Exposed in Pipeline Output | MEDIUM | T1552.001 | CICD-SEC-6 |
| FS026 | Unguarded Deploy — Deployment Job Runs on Untrusted Branches | HIGH | T1078 | CICD-SEC-1 |
Risk Score
Every scan produces a 0-100 risk score using severity-weighted diminishing returns and exponential normalization. A single critical finding scores ~28. A heavily vulnerable pipeline scores ~90-97. The score cannot exceed 100.
Rule Suppression
# CLI flag
flowsec scan --github --repo owner/repo --ignore FS006 --ignore FS011
# .flowsec.yml in your repo root
ignore:
- rule_id: FS006
reason: "We use external timeout management"
- rule_id: FS011
reason: "Branch protection managed at org level"
Use as a Pipeline Gate
name: FlowSec Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install flowsec
- run: flowsec scan --github --file .github/workflows/ci.yml --fail-on critical
Security
FlowSec is built to the same standard it enforces:
- All GitHub Actions pinned to commit SHAs with least-privilege permissions
- PyPI publishing via OIDC trusted publishing — no long-lived tokens
- Own CI runs gitleaks, bandit, pip-audit, and FlowSec self-scan on every push
- Branch protection on main — force push blocked, 4 required status checks
- YAML parsed with a SafeLoader subclass — no code execution risk
- HTML reports use Jinja2 autoescape — XSS from finding content prevented
Report vulnerabilities via GitHub Security Advisories or email Scorpio.vansh@gmail.com.
License
MIT — see LICENSE on GitHub.
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.5.4.tar.gz.
File metadata
- Download URL: flowsec-0.5.4.tar.gz
- Upload date:
- Size: 1.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bd0054504d38a3212bcb1b6b30e5ed611c26cebc23e8622cbefdbaa494cac32e
|
|
| MD5 |
b9707030f2d228ea1ea1f8d4f177b032
|
|
| BLAKE2b-256 |
e6792839ca7c8fad115073b84c42d7c0bbfa62dada32930c89ef0f8299b08d34
|
Provenance
The following attestation bundles were made for flowsec-0.5.4.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.5.4.tar.gz -
Subject digest:
bd0054504d38a3212bcb1b6b30e5ed611c26cebc23e8622cbefdbaa494cac32e - Sigstore transparency entry: 1737854930
- Sigstore integration time:
-
Permalink:
VanshBhardwaj1945/FlowSec@ac9a512375305eeef50e7616ceac374f19e50776 -
Branch / Tag:
refs/tags/v0.5.4 - Owner: https://github.com/VanshBhardwaj1945
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ac9a512375305eeef50e7616ceac374f19e50776 -
Trigger Event:
push
-
Statement type:
File details
Details for the file flowsec-0.5.4-py3-none-any.whl.
File metadata
- Download URL: flowsec-0.5.4-py3-none-any.whl
- Upload date:
- Size: 49.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb78b4b7caf8637c612e84f2757a6d5c2c3aff80f58e7ec3adb9829201bcea8a
|
|
| MD5 |
b1626448bdb0807d830d5089bf2a8055
|
|
| BLAKE2b-256 |
136d01c2cc9338252a1e1432a1060f76087d88d478e3d4699b0ed8fdde8bc8c4
|
Provenance
The following attestation bundles were made for flowsec-0.5.4-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.5.4-py3-none-any.whl -
Subject digest:
fb78b4b7caf8637c612e84f2757a6d5c2c3aff80f58e7ec3adb9829201bcea8a - Sigstore transparency entry: 1737854976
- Sigstore integration time:
-
Permalink:
VanshBhardwaj1945/FlowSec@ac9a512375305eeef50e7616ceac374f19e50776 -
Branch / Tag:
refs/tags/v0.5.4 - Owner: https://github.com/VanshBhardwaj1945
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ac9a512375305eeef50e7616ceac374f19e50776 -
Trigger Event:
push
-
Statement type: