🔐 Aysal-Scan
Detect leaked secrets in your git repos — and find out exactly what damage they can cause.
Every other tool tells you "you have a leaked key."
Aysal-Scan tells you "you have a leaked AWS key — it has AdministratorAccess on your production account. Here's how to fix it."
The Difference
| Feature | TruffleHog / GitLeaks | Aysal-Scan |
|---|---|---|
| Regex-based detection | ✅ | ✅ |
| Shannon entropy analysis | ✅ | ✅ |
| Git history scanning | ✅ | ✅ |
| Is the key still active? | ❌ | ✅ |
| What permissions does it have? | ❌ | ✅ |
| Plain English remediation | ❌ | ✅ |
| Severity score with blast radius | ❌ | ✅ |
| Scan any GitHub URL directly | ❌ | ✅ |
| Interactive UI mode | ❌ | ✅ |
Architecture
flowchart TD
A1[Local directory] --> DE
A2[Git history] --> DE
A3[GitHub URL] --> DE
A4[Staged changes] --> DE
DE["🔍 Detection engine
Regex · 17+ patterns · Shannon entropy"]
DE --> DD["Deduplication
SHA-256 per raw value"]
DD --> BR["💥 Blast radius engine
Live API verify · Permission enumeration
AWS · GitHub · OpenAI · Stripe · Slack · Twilio +12"]
BR --> SS["Severity scoring + remediation
CRITICAL → HIGH → MEDIUM → LOW"]
SS --> O1[Terminal / Rich UI]
SS --> O2[SARIF output]
SS --> O3[JSON / HTML]
style DE fill:#7F77DD,color:#fff,stroke:#534AB7
style DD fill:#888780,color:#fff,stroke:#5F5E5A
style BR fill:#D85A30,color:#fff,stroke:#993C1D
style SS fill:#1D9E75,color:#fff,stroke:#0F6E56
style O1 fill:#888780,color:#fff,stroke:#5F5E5A
style O2 fill:#888780,color:#fff,stroke:#5F5E5A
style O3 fill:#888780,color:#fff,stroke:#5F5E5A
Note: Live verification applies to most providers (AWS, GitHub, OpenAI, Stripe, Slack, Twilio, npm, SendGrid, Heroku, Google). PyPI, Azure, and GCP are flagged for manual review instead — no safe verify endpoint, no tenant ID available, and avoiding audit-log noise, respectively.
Real-World Demo
Scanning a test repo with a live canary AWS key:
aysal-scan scan https://github.com/trufflesecurity/test_keys
╭─────────────────────────── 🔴 [CRITICAL] AWS Access Key ────────────────────────────╮
│ File : new_key (line 2) │
│ Secret : AKIA************ZAM2 │
│ │
│ Blast Radius: │
│ Key status : ACTIVE │
│ Account : Account: 052310077262 | User: canarytokens.com@@c20nnjzl... │
│ Permission : Could not enumerate — insufficient IAM permissions │
│ │
│ Fix: 1. Go to AWS IAM Console → Users → Security Credentials │
│ 2. Deactivate this access key immediately │
│ 3. Rotate + store in AWS Secrets Manager │
│ 4. Remove from git history with: git filter-repo │
╰──────────────────────────────────────────────────────────────────────────────────────╯
✗ FAILED — secrets detected | Exit code: 1
The blast radius engine called
sts:GetCallerIdentityagainst live AWS, confirmed the key is active, retrieved the real account ID, and escalated severity to CRITICAL — all automatically.
Install
pip install aysal-scan
Or from source:
git clone https://github.com/Rolex-1905/aysal-scan
cd aysal-scan
pip install -e .
Requires Python 3.11+
Quick Start
# Scan current directory
aysal-scan scan .
# Interactive mode — guided, no flags needed
aysal-scan ui
All Commands
# ── Scan targets ────────────────────────────────────────────────────────────
aysal-scan scan . # current directory
aysal-scan scan /path/to/repo # specific path
aysal-scan scan secrets.env # single file
aysal-scan scan https://github.com/username/repo # GitHub URL (auto-clones)
# ── Git modes ───────────────────────────────────────────────────────────────
aysal-scan scan --staged # staged changes only
aysal-scan scan --commits 20 # last 20 commits
aysal-scan scan --full-history # entire git history
# ── Output formats ──────────────────────────────────────────────────────────
aysal-scan scan . --report json # JSON (for CI pipelines)
aysal-scan scan . --report html --output report.html # HTML report
# ── Filters & options ───────────────────────────────────────────────────────
aysal-scan scan . --min-severity HIGH # HIGH and CRITICAL only
aysal-scan scan . --no-blast-radius # skip API checks (offline)
aysal-scan scan . --no-fail # always exit 0
aysal-scan scan . --allow-list <id1>,<id2> # suppress known findings by ID
aysal-scan scan . --verbose # show detailed blast radius debug output
aysal-scan scan . --report sarif --sarif-baseline old.sarif # only alert on genuinely new findings
Supported Providers & Blast Radius Checks
| Secret Type | Detection | Blast Radius Check |
|---|---|---|
| AWS Access Key | Regex | sts:GetCallerIdentity → IAM policy list |
| GitHub Token (PAT / OAuth) | Regex | /user → scopes → repo access |
| OpenAI API Key | Regex | /v1/models → billing exposure |
| Stripe Secret Key | Regex | /v1/balance → live account access |
| Stripe Publishable Key | Regex | Auto LOW |
| Twilio Account SID | Regex | /Accounts/{SID} → status check |
| SendGrid API Key | Regex | /v3/scopes → permission list |
| Slack Bot Token | Regex | auth.test → workspace + permissions |
| Slack Webhook URL | Regex | Probe → active/inactive check |
| npm Token | Regex | registry.npmjs.org/-/whoami |
| PyPI Token | Regex | Manual review (no safe verify endpoint) |
| GCP Service Account JSON | JSON structure | Auto CRITICAL (project ID + client email parsed) |
| Azure Client Secret | Context-aware regex | Manual review (tenant ID required to verify) |
| Heroku API Key | Regex | /account → email + app access |
| Google API Key | Regex | Probe enabled APIs |
| JWT Token | Regex | Decode header + expiry check |
| Private Key (RSA / EC / SSH) | Regex | Auto CRITICAL |
| Database URL (Postgres, MySQL, Redis, MongoDB) | Regex | Auto HIGH |
| High Entropy String | Shannon entropy > 4.5 | Flagged for manual review |
Severity Levels
| Level | Meaning | Exit Code |
|---|---|---|
| 🔴 CRITICAL | Key is active + has admin/write access | 1 |
| 🟠 HIGH | Key is active + significant read access | 1 |
| 🟡 MEDIUM | Key appears valid but check failed or timed out | 0 |
| 🔵 LOW | Test/publishable key — limited exposure | 0 |
| ⚪ INFO | Likely a secret, unconfirmed | 0 |
Exit code 1 on any CRITICAL or HIGH finding. Override with --no-fail.
GitHub Actions
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Aysal-Scan Secret Scan
uses: Rolex-1905/aysal-scan@v1.0.0
with:
path: '.'
min-severity: 'HIGH'
no-blast-radius: 'false'
fail-on-findings: 'true'
- name: Upload HTML Report
uses: actions/upload-artifact@v4
if: always()
with:
name: aysal-scan-report
path: aysal-scan-report.html
retention-days: 30
- name: Upload SARIF to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: aysal-scan-results.sarif
category: aysal-scan
Pre-commit Hook
Recommended — remote repo mode (auto-installs, always up to date):
repos:
- repo: https://github.com/Rolex-1905/aysal-scan
rev: v1.0.0
hooks:
- id: aysal-scan # fast — no API calls, offline safe
With blast radius checks (slower — calls provider APIs):
repos:
- repo: https://github.com/Rolex-1905/aysal-scan
rev: v1.0.0
hooks:
- id: aysal-scan-with-blast-radius
Local mode (if you have aysal-scan already installed):
repos:
- repo: local
hooks:
- id: aysal-scan
name: Aysal-Scan — secret detection
entry: aysal-scan scan --staged --no-blast-radius
language: system
pass_filenames: false
Install pre-commit and activate:
pip install pre-commit
pre-commit install
Ignoring Files
Aysal-Scan automatically skips node_modules/, .git/, dist/, build/,
*.min.js, lock files, and binary files.
For custom rules, create an AysalScanignore file in your repo root
(same syntax as .gitignore):
# Ignore test fixtures with intentional fake keys
tests/test_cli.py
tests/test_patterns.py
# Ignore example config files
*.example
*.sample
config.example.env
How Blast Radius Works
When a secret is detected, Aysal-Scan calls the provider's API using read-only operations only to answer three questions:
- Is this key still active?
- What can it access?
- How bad is it if someone already has it?
All checks run concurrently with a 10-second timeout per provider.
A failed or timed-out check degrades gracefully to MEDIUM rather than
crashing the scan. The raw secret is never stored — only the masked value
(AKIA****XMPL) appears in any output or report.
Project Structure
aysal_scan/
├── cli.py # Typer CLI + interactive UI
├── models.py # Pydantic models (Finding, ScanReport, etc.)
├── scanner/
│ ├── patterns.py # Regex patterns for 17+ secret types
│ ├── entropy.py # Shannon entropy analysis
│ ├── file_scanner.py # File + directory scanning
│ ├── git_utils.py # Git history, staged, commit scanning
│ └── deduplicator.py # Deduplicate across commits
├── blast_radius/
│ ├── aws.py # AWS IAM checks via STS (user, group, inline policies)
│ ├── github.py # GitHub API scope check
│ ├── openai_checker.py # OpenAI key validation
│ ├── stripe.py # Stripe balance check
│ ├── slack.py # Slack auth.test
│ ├── slack_webhook.py # Slack webhook probe
│ ├── twilio.py # Twilio account check
│ ├── sendgrid.py # SendGrid scope list
│ ├── npm.py # npm whoami
│ ├── pypi.py # PyPI — flags for manual review (no safe verify endpoint)
│ ├── heroku.py # Heroku account check
│ ├── google.py # Google API probe
│ ├── gcp.py # GCP Service Account JSON parsing
│ ├── azure.py # Azure Client Secret — manual review
│ ├── jwt_checker.py # JWT decode + expiry
│ ├── base.py # Retry/backoff wrapper shared by all checkers
│ └── generic.py # Fallback for unknown types
└── reporter/
├── terminal.py # Rich-formatted terminal output
├── json_report.py # JSON output for CI
├── html_report.py # Interactive HTML report (collapsible, filterable)
└── sarif_report.py # SARIF 2.1.0 for GitHub Security tab
Tech Stack
Built with Python 3.11+ · Typer · Rich · Pydantic v2 · httpx · boto3 · GitPython
License
MIT © 2026 Aysal-Scan
Built by Neeraj Mudunuru
Metadata
Release files for aysal-scan 1.0.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 | |
|---|---|---|---|
| aysal_scan-1.0.2.tar.gz | 51.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aysal_scan-1.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 103.7 kB
Release files / aysal_scan-1.0.2.tar.gz
| Download URL | aysal_scan-1.0.2.tar.gz |
|---|---|
| Size | 51.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2c0e0e7fd5ce466618f6011f7ce49a5554b43c85c0d1915eeef290018f480b85
|
|
BLAKE2b-256 checksum How to use checksums |
1936d0817d28013a31beaefe9ab1576dbce342b6fd376b6bec272a01519a4da7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 20, 2026.
Transparency logRelease files / aysal_scan-1.0.2-py3-none-any.whl
| Download URL | aysal_scan-1.0.2-py3-none-any.whl |
|---|---|
| Size | 52.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
be46126312970298d217d3d399716c462948e5c817192b8252e4e88ef817a0f4
|
|
BLAKE2b-256 checksum How to use checksums |
53f1786fc0fe59d4321c9ed3c62c68f3cb40e041b74974cacec4720353ef2e92
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 20, 2026.
Transparency log