Bucket Scanner
Declared vs real.
Object Storage security scanner — Yandex Cloud · AWS S3 · Azure · GCS
What you configured · what ACL allows · what the internet can actually reach.
FluxTap · Tracefuse · Timeforge · SignShield · Bucket Scanner
Discussions · Issues · #devsecops · #cspm · #object-storage · #yandex-cloud · #aws-s3
Why
Buckets drift. ACL says private, policy leaks public-read. Versioning is off, logging never enabled, a service account key outlived three rotations — and nobody noticed until exfil.
Bucket Scanner walks your Object Storage across Yandex Cloud · AWS S3 · Azure Blob · GCS and surfaces gaps between what you declare and what actually ships:
| You declare | Bucket Scanner checks |
|---|---|
| Private bucket | Anonymous HEAD / list probe |
| Encryption at rest | Server-side encryption flags per bucket |
| Audit trail | Access logging enabled |
| Ransomware resilience | Versioning + lifecycle sanity |
| Least privilege | SA bindings → blast radius chains |
Metadata scan by default. Optional live probe proves reachability — without downloading object bodies.
╔══════════════════════════════════════════════════════════╗
║ BUCKET SCANNER ║
║ declared vs real · object storage truth ║
╚══════════════════════════════════════════════════════════╝
score 42 ████████░░░░░░░░░░░░
CRIT 1 HIGH 4 MED 7 LOW 2 INFO 3
CHAIN public-read + no-logging + stale-sa-key → silent exfil path
Part of the FounderB security stack: Tracefuse watches what you ship · FluxTap watches the wire · Bucket Scanner watches what you store.
Install
From PyPI (recommended):
pip install bucket-scanner
# pin: pip install bucket-scanner==1.9.2
bucket-scanner --help
From source (development):
git clone https://github.com/FounderB/BucketScanner.git
cd BucketScanner
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
make hooks # install local git author guard
See docs/PYPI.md for version pins and maintainer publishing.
Start here: docs/QUICKSTART.md · Golden demo: docs/GOLDEN_DEMO.md · Compliance: docs/COMPLIANCE.md
Requirements: Python 3.11+. No cloud credentials needed for the offline fixture demo (QUICKSTART). Live scans support Yandex Cloud, AWS S3, Azure Blob, and GCS equally — see docs/AWS.md, docs/AZURE.md, docs/GCS.md.
AWS S3 (optional)
export AWS_REGION=us-east-1
bucket-scanner scan --cloud aws
bucket-scanner scan --cloud aws --fixture examples/demo-vulnerable/fixture-aws.toml
bucket-scanner doctor --cloud aws
Azure Blob (live + fixture)
pip install "bucket-scanner[azure]"
export AZURE_SUBSCRIPTION_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
bucket-scanner scan --cloud azure --folder-id "$AZURE_SUBSCRIPTION_ID"
bucket-scanner scan --cloud azure --fixture examples/demo-vulnerable/fixture-azure.toml
bucket-scanner explain azure/container-public-access
Live scan uses DefaultAzureCredential (env vars, managed identity, Azure CLI). See docs/AZURE.md.
Google Cloud Storage (live + fixture)
pip install "bucket-scanner[gcs]"
export GCP_PROJECT=my-gcp-project
bucket-scanner scan --cloud gcs --folder-id "$GCP_PROJECT"
bucket-scanner scan --cloud gcs --fixture examples/demo-vulnerable/fixture-gcs.toml
See docs/GCS.md.
Live Azure scan: pip install 'bucket-scanner[azure]' — see docs/AZURE.md.
60-second wow
All values under examples/demo-vulnerable/ are labeled FAKE / EXAMPLE.
# Offline demo — no cloud credentials required
bucket-scanner scan --fixture examples/demo-vulnerable/fixture.toml
bucket-scanner scan --fixture examples/demo-vulnerable/fixture.toml --json
bucket-scanner scan --fixture examples/demo-vulnerable/fixture.toml \
--sarif /tmp/bucket-scanner.sarif --fail-on high
bucket-scanner scan --fixture examples/demo-vulnerable/fixture.toml \
--repo examples/demo-vulnerable/repo \
--tracefuse-report examples/demo-vulnerable/tracefuse-report.json \
--prometheus /tmp/bucket-scanner.prom
# Prometheus + continuous monitoring
bucket-scanner serve --fixture examples/demo-vulnerable/fixture.toml --addr 127.0.0.1:9090
# Prove public exposure (anonymous probe, no object download)
bucket-scanner scan --folder-id b1gxxxxxxxxxx --probe
Expect findings across acl, policy, encryption, logging, versioning, lifecycle, iam, and chains. Exit 1 when policy fails; exit 2 on tool error.
Quick start
export YC_TOKEN=$(yc iam create-token) # or YC_SERVICE_ACCOUNT_KEY_FILE
export YC_CLOUD_ID=b1g...
export YC_FOLDER_ID=b1g...
bucket-scanner scan --folder-id "$YC_FOLDER_ID"
bucket-scanner scan --folder-id "$YC_FOLDER_ID" --probe --fail-on high
bucket-scanner doctor # creds, scopes, API reachability
bucket-scanner explain acl/public-read # remediation + why
Live YC (doctor / scan against a real folder) needs YC_TOKEN (and usually YC_FOLDER_ID) — fixture smoke does not.
Probe mode sends unauthenticated HTTP requests to bucket endpoints to verify real-world exposure. It never downloads object payloads — only checks reachability metadata.
Features
| Detector | What it catches |
|---|---|
| acl | public-read, public-read-write, world-open grants |
| policy | Bucket policy statements wider than intent |
| encryption | Missing default encryption / SSE gaps |
| logging | No access logs on sensitive buckets |
| versioning | Versioning disabled on prod-like buckets |
| lifecycle | Aggressive expiration, incomplete multipart cleanup |
| iam | Over-broad SA roles, long-lived static keys |
| chains | Compound risk: public + no logs + no versioning + stale key |
Also: health score, bucket-scanner init → .bucket-scanner.toml, doctor / explain, severity overrides, quiet mode for CI, SARIF 2.1.0 for GitHub Code Scanning, diff for Terraform drift.
Terraform drift
bucket-scanner diff examples/demo-vulnerable/terraform \
--fixture examples/demo-vulnerable/fixture.toml
bucket-scanner scan --folder-id b1g... --terraform ./infra/storage/
Why not the console?
| YC Console / manual checklist | Bucket Scanner | |
|---|---|---|
| Scope | One bucket at a time | Whole folder · repeatable |
| Proof | ACL text says private | --probe proves anonymous reachability |
| Output | Screenshots in tickets | Redacted human / JSON / SARIF |
| Policy | Spreadsheet | --fail-on high · GitHub Action |
| Chains | Siloed findings | Misconfig graphs — why it hurts together |
| Drift | Point-in-time | CI on every PR · scheduled scans |
Use Bucket Scanner when you need one gate that answers “what does this folder actually risk?” — not just “is there a public ACL string somewhere?”
Who is this for?
| Audience | Fit |
|---|---|
| Platform / DevSecOps (5–50 people) | CI gate on Object Storage drift |
| Terraform + S3-compatible storage | IaC vs live ACL/BPA checks |
| YC / AWS primary | Most tested path; Azure/GCS supported |
| Full-account CSPM replacement | No — narrow storage focus |
5-minute path: docs/QUICKSTART.md · Rollout: docs/MIGRATION.md · OIDC CI: docs/OIDC.md
Comparison (honest)
| Bucket Scanner | Prowler / ScoutSuite | Checkov (storage rules) | |
|---|---|---|---|
| Focus | Object Storage only | Full cloud account | IaC static analysis |
| Live API + optional probe | Yes | Yes | No (IaC) |
| Terraform live drift | Yes | Limited | IaC only |
Baseline delta (fail-on new) |
Yes | Varies | Varies |
| Cross-stack (Tracefuse + repo) | Yes | No | Partial |
| SARIF + compliance JSON | Yes | Varies | Yes |
CLI
bucket-scanner init [--preset yc-prod|aws-prod|...] [--force] [path]
bucket-scanner doctor # creds, folder access, API health
bucket-scanner explain <rule-id> # remediation (e.g. acl/public-read)
bucket-scanner scan --folder-id ID # human report
bucket-scanner scan --folder-id ID --json # JSON to stdout
bucket-scanner scan --folder-id ID --sarif out.sarif --fail-on high
bucket-scanner scan --folder-id ID --baseline baselines/prod.json --fail-on new
bucket-scanner scan --folder-id ID --write-baseline baselines/prod.json
bucket-scanner scan --folder-id ID --probe # + anonymous reachability checks
bucket-scanner inspect BUCKET # single-bucket deep report
bucket-scanner chain --sa-id ID # blast radius from one SA
bucket-scanner diff PATH # Terraform vs live/fixture
bucket-scanner serve --addr 127.0.0.1:9090 # /metrics + /health
bucket-scanner list --folder-id ID # inventory summary
Exit codes: 0 clean / below threshold · 1 policy fail · 2 tool error.
Default fail_on in config is high (overridable via --fail-on or .bucket-scanner.toml).
Configuration
bucket-scanner init writes .bucket-scanner.toml:
[scan]
folder_id = "b1gxxxxxxxxxx"
fail_on = "high"
probe = false
[scan.ignore_buckets]
names = ["public-assets-cdn"]
[[scan.severity_overrides]]
rule = "versioning/disabled"
severity = "medium"
See docs/CONFIGURATION.md for full reference.
Architecture
flowchart LR
CLI["CLI<br/>scan · inspect · chain · doctor"] --> CFG[".bucket-scanner.toml"]
CFG --> SCAN["scan::run_scan"]
SCAN --> YC["YC Object Storage API<br/>metadata only"]
SCAN --> PROBE["probe::anonymous<br/>optional HEAD/list"]
YC --> DET["checks::*"]
PROBE --> DET
DET --> CHAIN["chains::compose"]
CHAIN --> OUT["report<br/>human · json · sarif"]
Details: docs/ARCHITECTURE.md · docs/CHECKS.md
GitHub Actions
Minimal scan + SARIF upload. Full guide: docs/GITHUB_ACTION.md.
name: bucket-scanner
on:
pull_request:
push:
branches: [main]
schedule:
- cron: "0 6 * * *"
permissions:
contents: read
security-events: write
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install .
- name: Scan YC folder
env:
YC_TOKEN: ${{ secrets.YC_TOKEN }}
YC_FOLDER_ID: ${{ secrets.YC_FOLDER_ID }}
run: |
bucket-scanner scan --folder-id "$YC_FOLDER_ID" \
--sarif bucket-scanner.sarif --fail-on high -q
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: bucket-scanner.sarif
Security promises
- Metadata by default — list buckets, ACLs, policies, settings; no bulk object download.
- Probe is opt-in — anonymous HTTP checks only when you pass
--probe. - Redaction — SA key fragments, tokens, and sensitive URLs redacted in all report formats.
- Offline fixtures —
examples/demo-vulnerable/uses clearly labeled FAKE/EXAMPLE values only.
See SECURITY.md and docs/AUDIT.md.
Roadmap
- Tracefuse hook — leaked
YC_*in repo → cross-finding - Prometheus exporter + Grafana dashboard
- Scheduled drift alerts (Telegram / webhook)
- AWS S3 backend (optional second cloud)
- Multi-region AWS inventory (per-bucket region resolution)
- Scheduled scan profiles in config
- CI/CD profile workflows (Action + scheduled matrix)
- Baseline/delta + suppressions for production CI gates
- Security hardening + audit docs (v0.11)
- PyPI package (
pip install bucket-scanner) - Azure Blob live scan (
pip install bucket-scanner[azure]) - GCS backend (fixture-first)
- GCS live scan (
pip install bucket-scanner[gcs]) - Golden demo walkthrough (docs/GOLDEN_DEMO.md)
- SARIF compliance tags (docs/COMPLIANCE.md)
- v1.0 stable — four-cloud live scan + PyPI + CI gates
- v1.1 — Terraform Azure/GCS drift, compliance export, Tracefuse polish
- v1.2 field deployment — prod profiles, baselines/, OIDC workflows (AWS/Azure/GCS), Grafana VM guide, multi-scope Azure/GCS
- v1.3 — medium-audience onboarding (QUICKSTART, presets, doctor, live-scan templates)
- v1.4–1.5 — live YC API fixes, Bucket.Get enrichment, ephemeral S3 keys, website/CORS findings
- v1.6 — multi-cloud security depth (BPA parity, blast-radius chains, Object Lock)
- v1.7 — ops product (suppression audit, hard baseline gate, per-rule metrics, Slack notify)
- v1.8 — calibration (PUBLIC_RULES FP, account BPA unknown, multi-cloud truthfulness)
- v1.9 — live proof tooling (
proof-log, daily fixture smoke, FP triage runbook)
Community
| Channel | Link |
|---|---|
| GitHub Discussions | FounderB/BucketScanner/discussions |
| Issues | FounderB/BucketScanner/issues |
GitHub topics: devsecops · cspm · object-storage · yandex-cloud · amazon-s3 · sarif · python
FounderB stack: Tracefuse (supply chain) · FluxTap (wire) · Bucket Scanner (object storage)
License
MIT © FounderB — LICENSE.
Contributing
Release files for bucket-scanner 1.9.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| bucket_scanner-1.9.2.tar.gz | 91.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bucket_scanner-1.9.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 171.0 kB
Release files / bucket_scanner-1.9.2.tar.gz
| Download URL | bucket_scanner-1.9.2.tar.gz |
|---|---|
| Size | 91.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f064f5072efa14d6a2bc0e46d02af2ef0dac84037b9a73be88e0045e0310c9cd
|
|
BLAKE2b-256 checksum How to use checksums |
f606ba3665a0a9eeb2b309f36683c283285373f836635600443908ac67039ed6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|
Release files / bucket_scanner-1.9.2-py3-none-any.whl
| Download URL | bucket_scanner-1.9.2-py3-none-any.whl |
|---|---|
| Size | 79.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2edd6bcae2553f1c66635a03723d0acc86f2f4d5480fa9249cf7a7f3f4c106b5
|
|
BLAKE2b-256 checksum How to use checksums |
956d1e8e6b78b5c79bde1edd56c155bbdeff1d597f884c102e2d82319b8ebaf7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|