Plexavo
An open-source AWS misconfiguration scanner that reads your account with
your own local AWS credentials — nothing is ever handed to anyone else.
Run it yourself, the same way you'd run aws s3 ls, and get a 0-100
security score plus a plain-English report explaining exactly what's
wrong, what an attacker would actually do with it, and the exact command
to fix it.
Deterministic detection (pure Python/boto3, never AI) finds the misconfigurations. Claude only rewrites already-computed technical findings into a narrative a non-security founder can act on — it never decides what counts as a finding, and it's entirely optional (see Cost below).
What it checks
31 checks across 6 categories, all validated against real, live AWS
accounts (not just offline logic) unless a specific, stated limitation
made that impossible — see the individual docs/*-TEST-MATRIX.md files
for exactly which checks are fully verified and which have a documented,
structural reason they can't be (e.g. some checks can only prove their
"clean" case without disabling a real security control to test the "bad"
case).
| Category | Checks | What it catches |
|---|---|---|
IAM (iam.py, iam_hygiene.py) |
14 | Privilege escalation paths, wildcard admin, cross-account trust, root usage, dormant credentials |
Network (network.py) |
4 | Security groups and RDS instances exposed to the internet |
Storage (storage.py) |
3 | Public S3 buckets, via ACLs, bucket policies, or missing Block Public Access |
Encryption (encryption.py) |
3 | Unencrypted EBS volumes, RDS instances, S3 default encryption |
Logging (logging.py) |
4 | CloudTrail coverage/encryption, GuardDuty status |
Usage analysis (usage.py) |
2 (+1 skipped, duplicate of an IAM check) | Granted permissions never actually used, roles nobody has assumed in 90+ days — the hardest category, built last, uses real CloudTrail history |
Plus scoring.py (the 0-100 score) and plexavo/report/ai_narration.py
(the opt-in AI layer).
Example output
Illustrative example (a public S3 bucket, an unencrypted volume, a role that's
never been assumed) — this is what a scan actually surfaces, including a
finding's free template remediation (shown by default, no --explain
needed; --explain would replace this panel with a full AI narrative
instead):
Your AWS Security Score: 74/100 (Good)
Findings (3)
┏━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Check ┃ Severity ┃ Resource ┃ Detail ┃
┡━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ STOR-19 │ Critical │ arn:aws:s3:::taskflow-uploads-prod │ Bucket 'taskflow-uploads-prod' allows │
│ │ │ │ public read via bucket policy. │
│ ENC-29 │ Medium │ vol-015506d04acb46ca9 │ EBS volume 'vol-015506d04acb46ca9' is not │
│ │ │ │ encrypted at rest. │
│ USE-27 │ High │ AWSSecurityScannerReadOnlyRole │ Role 'AWSSecurityScannerReadOnlyRole' has │
│ │ │ │ never been assumed since creation. │
└─────────┴──────────┴────────────────────────────────────┴────────────────────────────────────────────┘
╭────────────────────────────────────────── source: template ──────────────────────────────────────────╮
│ STOR-19 — arn:aws:s3:::taskflow-uploads-prod │
│ │
│ IMPACT: Bucket 'taskflow-uploads-prod' doesn't have full S3 Block Public Access protection enabled. │
│ Without this protection, a single mistake — an overly broad bucket policy, a public ACL grant, │
│ someone copy-pasting a policy from a tutorial — immediately exposes every object to anyone on the │
│ internet via a plain s3:GetObject call, with nothing left to catch the mistake. │
│ │
│ CONFIDENCE: Confirmed │
│ │
│ NEXT STEP: Turn on Block Public Access now: aws s3api put-public-access-block --bucket │
│ taskflow-uploads-prod --public-access-block-configuration │
│ "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true" │
│ │
│ FULL FIX DETAIL: Enable all four Block Public Access settings unless there's a specific, documented │
│ reason not to: │
│ aws s3api put-public-access-block --bucket taskflow-uploads-prod --public-access-block-configuration │
│ "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true" │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯
Severity, confidence, and evidence are always separate signals, never merged
into one label — a low-confidence Critical and a high-confidence Medium don't
read the same. This particular finding has no Evidence line because it's a
directly-observed fact with nothing uncertain about it — Evidence only appears
when a check has a concrete account-state fact behind it (e.g. an IAM policy
scoped by a Condition block, or a CloudTrail lookup that hit its page cap on
USE-26), and Confidence only drops from "Confirmed" in that same situation.
--report-html/--report-pdf render this same data as a full report; see
Cost for what --explain needs and what it costs.
Quick start
Recommended: uv. It installs Plexavo into its own isolated environment automatically — no venv to create, activate, or remember to reactivate in every new terminal.
1. Install uv (if you don't already have it)
curl -LsSf https://astral.sh/uv/install.sh | sh # Mac/Linux
powershell -c "irm https://astral.sh/uv/install.ps1 | iex" # Windows
(Full options: uv installation docs.)
2. Install Plexavo
uv tool install plexavo
That's it — plexavo is now on your PATH in every terminal, until you
uninstall it. No activate step, ever.
Have an Anthropic API key and want AI-narrated explanations (see
Cost — it's optional and costs a few cents per scan, not
free)? Install with the [ai] extra instead — same package, just with
the anthropic library included:
uv tool install "plexavo[ai]"
No key yet, or not sure? Skip it for now — the plain install is genuinely complete on its own. Add it later with:
uv tool install --reinstall "plexavo[ai]"
Just want to try it once without installing anything?
uvx plexavo scan --profile my-aws-profile
Updating or removing later:
uv tool upgrade plexavo
uv tool uninstall plexavo
3. Run a scan
plexavo scan --profile my-aws-profile --report-html report.html
No --profile? It uses your default profile / environment variables,
same resolution order as the AWS CLI. No AI, no API key, no cost — and
findings still come with free Next Step / Full Fix Detail guidance
wherever a template exists (10 common check types); this alone is a
complete, genuinely useful scan.
Want a full AI-written explanation for every finding instead (needs
the [ai] install above)?
export ANTHROPIC_API_KEY="sk-ant-..." # your own key, your own account
plexavo scan --profile my-aws-profile --explain --report-html report.html --report-pdf report.pdf
- Drop
--explainand findings still get free template remediation where available (no API key needed) and raw technical detail otherwise.--explainreplaces that with a live AI narrative for every finding, including the templated ones. - Drop
--report-html/--report-pdfto just see the console table. --explain-limit N(default 25) caps how many findings get a live AI call when--explainis passed, as a safety rail against unexpectedly large real scans — it doesn't limit the free template remediation.- No
ANTHROPIC_API_KEYset, or a call fails for any reason (invalid key, rate limit, network issue)? The scan and report are completely unaffected — that finding falls back to template/raw detail instead of an AI narrative, not an error. See Cost.
Alternative: pipx
Already use pipx? It works exactly the same way — its own isolated environment, one global command, no venv:
pipx install plexavo
pipx install "plexavo[ai]" # with AI-narrated explanations
Alternative: pip + venv
Prefer to manage the environment yourself, or on a system without uv/pipx?
Modern Python (PEP 668) blocks a plain pip install outside a venv on
many systems, so create one first:
python -m venv plexavo-env
plexavo-env\Scripts\activate # Windows
source plexavo-env/bin/activate # Mac/Linux
pip install plexavo
pip install "plexavo[ai]" # with AI-narrated explanations
You'll need to reactivate this venv (plexavo-env\Scripts\activate /
source plexavo-env/bin/activate) every time you open a new terminal —
deactivate exits it without uninstalling anything.
From source (for contributing, or trying an unreleased change)
git clone https://github.com/plexavo/plexavo.git
cd plexavo
uv pip install -e . # or: pip install -e . (inside a venv)
Project structure
plexavo/
├── auth.py # local AWS credential resolution
├── principals.py # enumerates IAM users/roles + their policies
├── findings.py # Finding data model, Severity enum
├── scoring.py # 0-100 score from a list of Findings
├── cli.py # `plexavo scan ...` entry point
├── checks/
│ ├── iam.py # IAM-01 to IAM-06 (privilege escalation)
│ ├── iam_hygiene.py # IAM-07 to IAM-14 (hygiene, cross-account trust)
│ ├── network.py # NET-01 to NET-04
│ ├── storage.py # STOR-19 to STOR-21
│ ├── encryption.py # ENC-29 to ENC-31
│ ├── logging.py # LOG-22 to LOG-25
│ └── usage.py # USE-26, USE-27
└── report/
├── html_report.py # assembles findings into HTML via Jinja2
├── pdf.py # same data, rendered to PDF via fpdf2
├── ai_narration.py # opt-in Claude narration + the 10 free templates
├── fonts/ # bundled DejaVu Sans (PDF) + Geist (HTML) —
│ both self-hosted, zero external requests
└── templates/report.html.j2 # the HTML report template
examples/
└── quickstart-sandbox.tf # one cheap, deliberately-public S3 bucket —
try the scanner without pointing it at
real infrastructure on day one
tests/
└── test_*.py # one per module, no AWS calls, run anytime:
python tests/test_iam_offline.py, etc.
docs/
├── *-TEST-MATRIX.md # one per category — the actual grading
│ record: what's verified, how, and any
│ stated limitation. Start here if you
│ want to know how much to trust a
│ given check.
├── COMPARISON.md # honest, hands-on comparison against
│ Prowler, ScoutSuite, and PMapper
├── TECHNICAL-EXPLAINER.md # implementation decisions and why
└── HOW-IT-WORKS.md
Cost
Detection is free (pure Python/boto3), always, regardless of anything else in this section. Every scan also gets free Next Step / Full Fix Detail remediation wherever one of 10 hand-written templates matches the finding type — no flag, no API key, zero cost, on by default.
Live AI only runs with --explain, and when it does it's used for
every finding, including the 10 templated ones (a deliberate choice —
"AI narration on" always means fully AI-written content, not a mix of
template and AI), typically $0.01-0.02 per finding depending on answer
length. A full scan with --explain on a real account is usually well
under a dollar. This is your own ANTHROPIC_API_KEY, in your own
Anthropic account — this project never sees your key, never embeds one of
its own, and never calls the API on your behalf without you having set
one. Not "free AI" — bring your own key, and a scan with it enabled costs
a few cents.
Running the tests
pip install -e ".[dev]"
for f in tests/test_*.py; do python "$f"; done
Each is self-contained — fake AWS API responses, no real credentials or
network calls needed. See docs/TEST-MATRIX.md for how these map to
live-AWS verification.
Contributing
See CONTRIBUTING.md — in particular, the pattern for
adding a new check.
Security
Found a vulnerability in the tool itself (not a misconfiguration in your
own AWS account — that's the tool working correctly)? See
SECURITY.md for a private reporting path.
License
AGPL-3.0 — see LICENSE. You can use, run, and modify this
freely. If you run a modified version as a hosted service, you're
required to publish those modifications too. This is deliberate: it's
the specific protection against a well-resourced company taking this
code and standing up a competing hosted product without ever
contributing back.
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 plexavo-0.2.0.tar.gz.
File metadata
- Download URL: plexavo-0.2.0.tar.gz
- Upload date:
- Size: 1.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a7983229977775c2a5722c165b992a007ece61382d208e797c02ec204bb9698
|
|
| MD5 |
7cc6cbc6c4c7ba281e6abb92b808cb09
|
|
| BLAKE2b-256 |
b16131f69a74350e3f623dcee978370f01f6f6dc67a3ed294104d26a257e6639
|
Provenance
The following attestation bundles were made for plexavo-0.2.0.tar.gz:
Publisher:
publish.yml on plexavo/Plexavo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
plexavo-0.2.0.tar.gz -
Subject digest:
0a7983229977775c2a5722c165b992a007ece61382d208e797c02ec204bb9698 - Sigstore transparency entry: 2607087797
- Sigstore integration time:
-
Permalink:
plexavo/Plexavo@3c8dd74a49f72fa9ebecf6052f29afe8704bcd9c -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/plexavo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@3c8dd74a49f72fa9ebecf6052f29afe8704bcd9c -
Trigger Event:
push
-
Statement type:
File details
Details for the file plexavo-0.2.0-py3-none-any.whl.
File metadata
- Download URL: plexavo-0.2.0-py3-none-any.whl
- Upload date:
- Size: 1.6 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e02215d6c2d65865843e340efc83fdd9ef6960ebad44acef81ef3abfccf3270
|
|
| MD5 |
bdce6d6e20619315e5fd0fffb7d816f7
|
|
| BLAKE2b-256 |
acbd63b10af855ef98977f740ec5cc83d27b565a85224b6923f0862813792e21
|
Provenance
The following attestation bundles were made for plexavo-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on plexavo/Plexavo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
plexavo-0.2.0-py3-none-any.whl -
Subject digest:
3e02215d6c2d65865843e340efc83fdd9ef6960ebad44acef81ef3abfccf3270 - Sigstore transparency entry: 2607089520
- Sigstore integration time:
-
Permalink:
plexavo/Plexavo@3c8dd74a49f72fa9ebecf6052f29afe8704bcd9c -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/plexavo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@3c8dd74a49f72fa9ebecf6052f29afe8704bcd9c -
Trigger Event:
push
-
Statement type: