AI-powered vulnerability scanner for Nigerian developers and global SMBs
Project description
Permi
AI-Powered Vulnerability Scanner for Nigerian Developers
What is Permi?
Permi is an AI-powered security scanner that finds real vulnerabilities in web applications and source code — and filters out the false positives that waste your time.
Traditional scanners flag hundreds of issues. Most are noise. Permi uses an AI filter to confirm which findings are real before showing them to you, so you spend time fixing vulnerabilities, not chasing ghosts.
Built from Jos, Nigeria. For Nigerian developers. Then for the world.
Quick Start
pip install permi
permi scan --url https://yoursite.com
⚠️ Windows Users — If Permi Freezes on First Run
Some Windows machines freeze immediately when running permi — even before the banner appears. This is caused by Windows Defender or corporate antivirus scanning Python processes in real time.
Fix — add Permi to your antivirus exclusions:
- Open Windows Security → Virus & threat protection → Manage settings
- Scroll to Exclusions → Add an exclusion → Folder
- Add these two folders:
C:\Users\<yourname>\.permiC:\Users\<yourname>\Permi\venv(or wherever your venv lives)
- Open a new terminal and run
permiagain
If you are on a corporate machine or university network, your IT department may have group policies that block Python subprocess calls. In that case, run Permi from Windows Subsystem for Linux (WSL) instead:
wsl
pip install permi
permi scan --path ./myapp
Installation
pip install permi
Requires Python 3.9+. Works on Windows, macOS, and Linux.
For JavaScript/SPA scanning (React, Vue, Angular, Next.js)
pip install playwright
playwright install chromium
Note for low-RAM machines (4GB): Use
--max-pages 10with--jsto keep memory usage manageable.
Usage
Scan a live website (standard HTTP)
permi scan --url https://yoursite.com
Scan a JavaScript-rendered application (React / Vue / Angular / Next.js)
permi scan --url https://yoursite.com --js
The --js flag launches a headless Chromium browser that fully renders JavaScript before scanning. Required for single-page applications where links and forms are built dynamically.
Without --js, Permi will detect a SPA and show:
[Permi] ⚠️ JavaScript-rendered application detected.
[Permi] Re-run with --js to scan the full JavaScript-rendered content:
[Permi] permi scan --url https://yoursite.com --js
Scan a local codebase
permi scan --path ./myapp
Scan a GitHub repository
permi scan --path https://github.com/username/repo
Include subdomains
permi scan --url https://yoursite.com --include-subdomains
High severity findings only
permi scan --url https://yoursite.com --severity high
Export results to a file
permi scan --url https://yoursite.com --export report.md
permi scan --path ./myapp --export results.json
permi scan --path ./myapp --export results.txt
Show all raw findings (skip AI filter)
permi scan --url https://yoursite.com --offline
JSON output (for CI/CD pipelines)
permi scan --url https://yoursite.com --output json
Setting Up AI Filtering
Your own OpenRouter API key (unlimited)
permi setup --api-key YOUR_KEY
Get a free key at openrouter.ai.
GitHub Action — Scan Every Pull Request
Add Permi to your CI/CD pipeline so every pull request is automatically scanned. Findings are posted as a PR comment and the merge is blocked if high severity issues are found.
# .github/workflows/security.yml
name: Security Scan
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
permi-scan:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: Peternasarah/permi-action@v1
with:
severity: high
openrouter_api_key: ${{ secrets.OPENROUTER_API_KEY }}
What happens on every PR:
- Permi scans the changed code
- AI filter removes false positives
- Findings posted as a PR comment
- Merge blocked if high severity issues found
→ View Permi GitHub Action on the Marketplace
How It Works
┌─────────────┐ ┌──────────────┐ ┌─────────────┐ ┌──────────────┐
│ Crawler │───▶│ Scanner │───▶│ AI Filter │───▶│ Results │
│ HTTP or JS │ │ SQL · XSS │ │ Real vs FP │ │ Confirmed │
│ (--js) │ │ Headers · + │ │ 78% noise │ │ findings │
└─────────────┘ └──────────────┘ │ reduction │ └──────────────┘
└─────────────┘
Two crawler modes:
- HTTP mode (default) — fast BeautifulSoup crawler for server-rendered sites
- JS mode (
--js) — Playwright headless Chromium for React/Vue/Angular SPAs
AI filter features:
- Confirms or dismisses each finding individually
- CSP-aware: knows when a reflected XSS cannot execute due to Content-Security-Policy
- Caches results to save API credits on repeated scans
- Three-tier verdict: REAL / REVIEW / FP with confidence score 0-100
- Community proxy for users without their own API key
What Permi Detects
Web scanning (--url)
| Category | What is detected |
|---|---|
| SQL Injection | Error-based, Boolean-based blind, Time-based blind |
| Cross-Site Scripting | Reflected XSS across all parameters |
| Missing Security Headers | CSP, HSTS, X-Frame-Options, Permissions-Policy |
| Server Information Disclosure | Server header, X-Powered-By version leakage |
Source code scanning (--path)
| Category | What is detected |
|---|---|
| SQL Injection | String concatenation, f-strings, % formatting in queries |
| Cross-Site Scripting | innerHTML, document.write, Jinja2 |safe filter |
| Hardcoded Secrets | Passwords, API keys, AWS keys, Paystack/Flutterwave secrets |
| Insecure Practices | eval(), exec(), pickle.loads(), SSL verification disabled, debug mode |
| USSD Vulnerabilities | Unvalidated sessionId, phoneNumber, serviceCode |
Nigerian-Specific Rules
Permi includes rules built specifically for the Nigerian development context:
- USSD gateway vulnerabilities — unvalidated sessionId, phoneNumber, serviceCode
- Paystack and Flutterwave key exposure — detects Nigerian payment gateway secrets
- NDPR-relevant patterns — helps with Nigeria Data Protection Act compliance
No foreign scanner understands this market the way Permi does.
Example Output
[Permi] Mode : JS scan (Playwright headless browser)
[Permi] Target : https://yourapp.com
[Permi] Crawl : up to 30 pages (JS-rendered)
[Permi JS] Rendering page 1/30: https://yourapp.com
[Permi JS] Rendering page 2/30: https://yourapp.com/login
[Permi JS] Crawl complete — 8 pages rendered, 24 URLs found, 12 unique signatures
[Permi] Engine found 7 raw finding(s)
[Permi] Running AI filter on 7 finding(s)...
════════════════════════════════════════════════════════════════════════
AI FILTER SUMMARY
════════════════════════════════════════════════════════════════════════
Raw findings : 7
Confirmed real : 4
False positives : 3 removed
Noise reduced by : 43% [████████░░░░░░░░░░░░]
Avg confidence : 89%
Severity breakdown:
● High : 2
● Medium : 2
Top issues to fix:
• 2× SQL Injection — string concatenation
• 1× Hardcoded secret — generic password
• 1× Insecure — SSL/TLS verification disabled
════════════════════════════════════════════════════════════════════════
[1] [HIGH] WEB_SQL001 SQL Injection — Error-based
URL : https://yourapp.com/login
Parameter : username
Fix : Use parameterised queries: cursor.execute("SELECT * FROM users WHERE name = ?", (name,))
AI : REAL [94% confidence] SQL syntax error confirms input reaches query unescaped.
Scan completed in 2 min 14s | 12 URLs tested
CLI Reference
permi scan --url URL Scan a live website
--js Use Playwright for JS-rendered SPAs
--include-subdomains Also scan subdomains
--max-pages N Max pages to crawl (default: 30)
--severity LEVEL high | medium | low | all (default: all)
--offline Skip AI filter, show raw findings
--output FORMAT human (default) | json
--export FILE Export full report (.txt, .json, .md)
permi scan --path PATH Scan local codebase or GitHub repo
--severity LEVEL Filter by severity
--offline Skip AI filter
--output FORMAT human | json
--export FILE Export full report
permi setup --api-key KEY Use your own OpenRouter API key
permi info Show config, credits, Playwright status
permi feedback Share feedback with the Permi team
CI/CD Integration
Permi exits with code 1 if any HIGH severity findings are confirmed. Use this in any pipeline:
# GitHub Actions — inline (without the Marketplace Action)
- name: Run Permi security scan
run: |
pip install permi
permi setup --api-key ${{ secrets.OPENROUTER_API_KEY }}
permi scan --path . --severity high --output json --export permi-report.json
# Fail the build on high severity findings
permi scan --path ./myapp --severity high || exit 1
Changelog
v0.2.13 — JS/SPA Support + GitHub Action
- NEW:
--jsflag for JavaScript-rendered applications (React, Vue, Angular, Next.js, Nuxt) - NEW: Playwright headless browser integration via
scanner/js_crawler.py - NEW: Network interception — discovers XHR/fetch API endpoints automatically
- NEW: Search box interaction — fills and submits search inputs to reveal parameterised URLs
- NEW: Clear SPA detection warning with exact
--jscommand shown to user - NEW:
permi infonow shows Playwright installation status - NEW: Permi GitHub Action — scan every PR automatically
- NEW: Windows antivirus freeze detection and guidance
v0.2.13 — Accuracy & Speed
- FIX: CSP-aware XSS analysis — AI now correctly dismisses reflected XSS blocked by CSP
- FIX: Concurrent scanning — SQL and XSS run in parallel per URL via
asyncio.gather()(~50% speed improvement) - FIX: URL deduplication — same endpoint scanned only once
- FIX: Boolean SQL threshold raised; known redirect-page sizes filtered
- FIX: Time-based SQL reduced to MySQL SLEEP only; 10s hard cap; 6s threshold
- NEW: Scan timer — total scan duration shown in summary
v0.2.2 — AI Filter + Community Proxy
- AI false-positive filter with 78% noise reduction
- Three-tier verdict: REAL / REVIEW / FP with 0-100 confidence score
- OpenRouter API key support with priority chain
- Fix templates — inline remediation per finding
--exportflag — save full reports as .txt, .json, or .md--include-subdomainsflag for subdomain-aware web scanning- Feedback system —
permi feedbacksubmits to Google Forms
v0.1 — Foundation
- CLI scanner (web + static analysis)
- PyPI distribution (
pip install permi) - 17 detection rules across SQL, XSS, secrets, USSD, insecure practices
- SQLite database at
~/.permi/permi.db
Contributing
Pull requests welcome. Please open an issue first to discuss what you want to change.
If you find a vulnerability in a real Nigerian application using Permi, consider reporting it responsibly to the affected organisation before disclosing publicly.
Author
Nasarah Peter Dashe Founder · Cybersecurity Student @ University of Jos, Nigeria github.com/Peternasarah/permi · @peternasarah
Links
- Website: peternasarah.github.io/permi
- PyPI: pypi.org/project/permi
- GitHub Action: github.com/marketplace/actions/permi-security-scanner
- Issues: github.com/Peternasarah/permi/issues
- Security: SECURITY.md
- License: LICENSE
License
PERMI COMMUNITY LICENSE — see LICENSE for details.
Built in Nigeria. For Nigeria. Then for the World.
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 permi-0.2.16.tar.gz.
File metadata
- Download URL: permi-0.2.16.tar.gz
- Upload date:
- Size: 54.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eff1bc1e334986f8c7311146301c49b6932094d1ee924928738d0bedbde81c5e
|
|
| MD5 |
35c2950adf8ade399ed17860c82cb4eb
|
|
| BLAKE2b-256 |
c22dd5f76823be883def47985572cd8c3b300c323d05c9687edeb823f89441ce
|
File details
Details for the file permi-0.2.16-py3-none-any.whl.
File metadata
- Download URL: permi-0.2.16-py3-none-any.whl
- Upload date:
- Size: 54.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0d967e43e26d613bdd5d40a65d07340388ae7fd002db2a2486e1ccf6872162f7
|
|
| MD5 |
b2dca3743dc3335e941ea41cdd688506
|
|
| BLAKE2b-256 |
2dd658cb717098d68143cfa1036f5a9145ad4627fa0966884fadf3ed5d358e24
|