Metadata-Version: 2.4
Name: flowsec
Version: 0.7.0
Summary: CI/CD pipeline security analyzer — scans GitHub Actions, GitLab CI, and Azure DevOps configs for attack vectors
Author-email: Vansh Bhardwaj <Scorpio.vansh@gmail.com>
License: MIT
License-File: LICENSE
Keywords: cicd,devsecops,github-actions,pipeline-security,sast,security
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Security
Requires-Python: >=3.11
Requires-Dist: jinja2>=3.1.4
Requires-Dist: python-dotenv>=1.0.1
Requires-Dist: pyyaml>=6.0.1
Requires-Dist: rich>=13.7.0
Provides-Extra: ai
Requires-Dist: anthropic>=0.40.0; extra == 'ai'
Provides-Extra: dev
Requires-Dist: anthropic>=0.40.0; extra == 'dev'
Requires-Dist: bandit>=1.7.8; extra == 'dev'
Requires-Dist: hatch>=1.12.0; extra == 'dev'
Requires-Dist: httpx>=0.27.0; extra == 'dev'
Requires-Dist: mypy>=1.10.0; extra == 'dev'
Requires-Dist: pygithub>=2.1.1; extra == 'dev'
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
Requires-Dist: pytest-mock>=3.14.0; extra == 'dev'
Requires-Dist: pytest>=8.2.0; extra == 'dev'
Requires-Dist: python-gitlab>=4.4.0; extra == 'dev'
Requires-Dist: responses>=0.25.3; extra == 'dev'
Requires-Dist: ruff>=0.4.4; extra == 'dev'
Requires-Dist: types-pyyaml>=6.0.1; extra == 'dev'
Provides-Extra: remote
Requires-Dist: httpx>=0.27.0; extra == 'remote'
Requires-Dist: pygithub>=2.1.1; extra == 'remote'
Requires-Dist: python-gitlab>=4.4.0; extra == 'remote'
Description-Content-Type: text/markdown

# 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):**

```bash
brew install VanshBhardwaj1945/flowsec/flowsec
```

**PyPI:**

```bash
pip install flowsec                # local file/directory scanning
pip install "flowsec[remote]"      # + remote repo scanning
pip install "flowsec[ai]"          # + AI attack narratives
```

---

## Quick Start

```bash
# Scan your repo checkout (finds .github/workflows/ automatically)
flowsec scan --github --dir .

# Scan a remote GitHub repo (public repos work without a 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

# JSON to stdout — pipe it anywhere
flowsec scan --github --dir . --format json

# SARIF for GitHub code scanning
flowsec scan --github --dir . --format sarif --output results.sarif

# Generate an HTML report
flowsec scan --github --dir . --format html --output report.html

# Generate AI attack narratives (requires ANTHROPIC_API_KEY)
flowsec scan --github --dir . --ai

# Fail pipeline if findings at or above threshold
flowsec scan --github --dir . --fail-on critical

# Ignore specific rules
flowsec scan --github --dir . --ignore FS006 --ignore FS011
```

Exit codes: `0` clean scan, `1` when `--fail-on` triggers, `2` for usage or scan errors.

---

## Platforms and Tokens

| Platform | Local scan | Remote scan | Token |
|---|---|---|---|
| GitHub Actions | `--github --file` or `--dir` | `--github --repo owner/repo` | `GITHUB_TOKEN` — optional for public repos |
| GitLab CI | `--gitlab --file` or `--dir` | `--gitlab --repo namespace/project` | `GITLAB_TOKEN` (remote only) |
| Azure DevOps | `--azure --file` or `--dir` | `--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. Remote scanning needs `pip install "flowsec[remote]"`.

---

## 38 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 |
| FS027 | Docker Socket Mounted — Full Host Control from Pipeline | CRITICAL | T1611 | CICD-SEC-7 |
| FS028 | Credential in Git URL — Token Leaked to Logs and History | HIGH | T1552.001 | CICD-SEC-6 |
| FS029 | github-script Injection — Untrusted Event Data in Inline Script | CRITICAL | T1059.004 | CICD-SEC-4 |
| FS030 | secrets: inherit — All Secrets Passed to Called Workflow | MEDIUM | T1078 | CICD-SEC-5 |
| FS031 | Cache Poisoning Risk — Cache Used With Privileged Trigger | HIGH | T1195.001 | CICD-SEC-3 |
| FS032 | Unpinned Remote Include — External Pipeline Config Pulled at Runtime | HIGH | T1195.001 | CICD-SEC-3 |
| FS033 | Unsecure Commands Enabled — Deprecated set-env Injection Re-Enabled | HIGH | T1059.004 | CICD-SEC-4 |
| FS034 | Plain-HTTP Download — Unencrypted Fetch in Pipeline | MEDIUM | T1071 | CICD-SEC-3 |
| FS035 | Environment File Injection — Untrusted Data Written to GITHUB_ENV | HIGH | T1059.004 | CICD-SEC-4 |
| FS036 | Persist Credentials — Azure Checkout Leaves Token in Git Config | MEDIUM | T1552.001 | CICD-SEC-6 |
| FS037 | Obfuscated Execution — Encoded Payload Piped to a Shell | MEDIUM | T1027 | CICD-SEC-3 |
| FS038 | Docker-in-Docker Service — Privileged Runner Required | HIGH | T1611 | CICD-SEC-7 |

---

## 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

```bash
# CLI flag
flowsec scan --github --repo owner/repo --ignore FS006 --ignore FS011

# .flowsec.yml in your repo root
```

```yaml
ignore:
  - rule_id: FS006
    reason: "We use external timeout management"
  - rule_id: FS002
    file: "legacy/*.yml"
    reason: "Legacy pipelines are being retired, not fixed"
```

The optional `file` field limits the ignore to files matching a glob.

---

## Use as a Pipeline Gate

```yaml
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 --dir . --fail-on critical
```

Or upload SARIF to GitHub's Security tab:

```yaml
      - run: flowsec scan --github --dir . --format sarif --output flowsec.sarif
      - uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: flowsec.sarif
```

---

## 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.

**Source:** https://github.com/VanshBhardwaj1945/FlowSec
