A CLI security inspection tool for Python API frameworks
Project description
ApiPosture
A CLI security inspection tool for Python API frameworks. Performs static source-code analysis to identify authorization misconfigurations and security risks.
Features
- Multi-Framework Support: FastAPI, Flask, Django REST Framework
- 8 Security Rules: Comprehensive detection of common authorization issues
- Multiple Output Formats: Terminal (Rich), JSON, Markdown
- Configurable: YAML-based configuration with suppressions
- CI/CD Ready: Exit codes based on severity for pipeline integration
Installation
pip install apiposture
Quick Start
# Scan current directory
apiposture scan .
# Scan specific path with JSON output
apiposture scan ./src --output json
# Scan and fail on high severity findings (for CI)
apiposture scan . --fail-on high
Security Rules
| Rule | Name | Severity | Description |
|---|---|---|---|
| AP001 | Public without explicit intent | High | Public endpoint without AllowAny or explicit marker |
| AP002 | Anonymous on write | High | AllowAny on POST/PUT/DELETE/PATCH |
| AP003 | Auth conflict | Medium | Method-level AllowAny overrides class auth |
| AP004 | Missing auth on writes | Critical | No auth on write endpoints |
| AP005 | Excessive roles | Low | >3 roles on single endpoint |
| AP006 | Weak role naming | Low | Generic names like "user", "admin" |
| AP007 | Sensitive keywords | Medium | admin/debug/export in public routes |
| AP008 | Endpoint without auth | High | No auth configuration at all |
Supported Frameworks
FastAPI
from fastapi import Depends, FastAPI
@app.get("/protected")
async def protected(user = Depends(get_current_user)):
...
Flask
from flask import Flask
from flask_login import login_required
@app.route("/protected")
@login_required
def protected():
...
Django REST Framework
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
class ProtectedView(APIView):
permission_classes = [IsAuthenticated]
Configuration
Create .apiposture.yaml in your project root:
rules:
disabled:
- AP006 # Disable weak role naming check
exclude:
- "**/tests/**"
- "**/migrations/**"
suppressions:
- rule: AP001
route: "/health"
reason: "Health check is intentionally public"
CLI Options
apiposture scan [PATH] [OPTIONS]
Options:
-o, --output Output format: terminal, json, markdown
-f, --output-file Write output to file
-c, --config Configuration file path
--severity Minimum severity: info, low, medium, high, critical
--fail-on Exit code 1 if findings at this severity
--sort-by Sort by: severity, route, method, classification
--classification Filter: public, authenticated, role_restricted
--method Filter: GET, POST, PUT, DELETE, PATCH
--route-contains Filter routes by substring
--framework Filter: fastapi, flask, django_drf
--rule Filter by rule ID
--no-color Disable colored output
--no-icons Disable icons
Development
# Clone the repository
git clone https://github.com/apiposture/apiposture-python
cd apiposture-python
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run linter
ruff check src tests
# Run type checker
mypy src
License
MIT
Project details
Release history Release notifications | RSS feed
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 apiposture-1.0.6.tar.gz.
File metadata
- Download URL: apiposture-1.0.6.tar.gz
- Upload date:
- Size: 33.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
01b39535a9e73576fd7d0db8f7948ccc4d8255ab80a6b76f98ae888ca5919325
|
|
| MD5 |
9dd494e4158080e488dc325f8f2e2e9c
|
|
| BLAKE2b-256 |
c87b003edc7d0c32b7aea28d479c77d3abf61cfeb3d2cd540a8a33924d22c332
|
Provenance
The following attestation bundles were made for apiposture-1.0.6.tar.gz:
Publisher:
publish.yml on BlagoCuljak/ApiPosture.Python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
apiposture-1.0.6.tar.gz -
Subject digest:
01b39535a9e73576fd7d0db8f7948ccc4d8255ab80a6b76f98ae888ca5919325 - Sigstore transparency entry: 1029688715
- Sigstore integration time:
-
Permalink:
BlagoCuljak/ApiPosture.Python@7c7fc972abec1922aad9e942e330560e45762e6a -
Branch / Tag:
refs/tags/v1.0.6 - Owner: https://github.com/BlagoCuljak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7c7fc972abec1922aad9e942e330560e45762e6a -
Trigger Event:
release
-
Statement type:
File details
Details for the file apiposture-1.0.6-py3-none-any.whl.
File metadata
- Download URL: apiposture-1.0.6-py3-none-any.whl
- Upload date:
- Size: 54.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9e5514342bad96997a03753b48147ab303885b40b863c7c5a87878acbb1108dd
|
|
| MD5 |
ad5dcb65e27d4df2ae51e5bc69e48363
|
|
| BLAKE2b-256 |
eae22fdc19360fde1f891fedf64473a652a8e224c474054dd20dfe2e71ea2c46
|
Provenance
The following attestation bundles were made for apiposture-1.0.6-py3-none-any.whl:
Publisher:
publish.yml on BlagoCuljak/ApiPosture.Python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
apiposture-1.0.6-py3-none-any.whl -
Subject digest:
9e5514342bad96997a03753b48147ab303885b40b863c7c5a87878acbb1108dd - Sigstore transparency entry: 1029688737
- Sigstore integration time:
-
Permalink:
BlagoCuljak/ApiPosture.Python@7c7fc972abec1922aad9e942e330560e45762e6a -
Branch / Tag:
refs/tags/v1.0.6 - Owner: https://github.com/BlagoCuljak
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7c7fc972abec1922aad9e942e330560e45762e6a -
Trigger Event:
release
-
Statement type: