Bucket Scanner
Declared vs real. Object Storage security scanner (Yandex Cloud + AWS S3 + Azure preview).
What you configured · what ACL allows · what the internet can actually reach.
FluxTap · Tracefuse · Timeforge · SignShield · Bucket Scanner
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 (Yandex Cloud by default, AWS S3 optional) 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
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.
Requirements: Python 3.11+, Yandex Cloud credentials (default) or AWS credentials (--cloud aws). See docs/AWS.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.
Live Azure inventory is planned; 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
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?”
CLI
bucket-scanner init [--force] [path] # write .bucket-scanner.toml
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
License
MIT © FounderB — LICENSE.
Contributing
Release files for bucket-scanner 0.13.0
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-0.13.0.tar.gz | 58.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bucket_scanner-0.13.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 111.6 kB
Release files / bucket_scanner-0.13.0.tar.gz
| Download URL | bucket_scanner-0.13.0.tar.gz |
|---|---|
| Size | 58.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2948c46e5bc5220ef688b847d266ea9886854d3eae57c3e50409a0dc5f69c74b
|
|
BLAKE2b-256 checksum How to use checksums |
dfb66582cb8a92e2dd5c1c2a6255ae8bcb7789587a256a471f9516fa426f319d
|
| 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-0.13.0-py3-none-any.whl
| Download URL | bucket_scanner-0.13.0-py3-none-any.whl |
|---|---|
| Size | 53.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
17b5c1be05345c39753a544b3590e064eeb919a1972f8ee1e87fd2fefc0f1054
|
|
BLAKE2b-256 checksum How to use checksums |
0c10cd247cccc1e0090e4d815ac4a2280cbee4c61fb6819378b0fe62ccf7361f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|