penthera 1.1.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +269 -3
- package/README.md +489 -286
- package/SECURITY.md +28 -6
- package/docs/METHODOLOGY.md +321 -0
- package/docs/compliance-nis2.md +166 -0
- package/docs/evidence.md +158 -0
- package/docs/examples/github-actions-deps.yml +105 -0
- package/docs/examples/github-actions-scan.yml +55 -0
- package/docs/examples/pr-dependency-review.yml +56 -0
- package/docs/funding/due-diligence-checklist.md +79 -0
- package/docs/funding/nlnet-ngi-zero-draft.md +273 -0
- package/docs/funding/partner-one-pager.md +84 -0
- package/docs/funding/sponsor-tiers.md +81 -0
- package/docs/index.md +15 -3
- package/docs/local-loop.md +276 -0
- package/docs/references.bib +539 -0
- package/docs/references.md +77 -0
- package/docs/release-plan.md +228 -0
- package/lib/adaptive-probes.js +8 -5
- package/lib/agents/discover.js +384 -0
- package/lib/agents/hidden-content.js +387 -0
- package/lib/agents/index.js +286 -0
- package/lib/agents/lock.js +115 -0
- package/lib/agents/owasp.js +83 -0
- package/lib/agents/rules.js +376 -0
- package/lib/crawler.js +5 -15
- package/lib/data/retire-jsrepository.json.gz +0 -0
- package/lib/data/retire-jsrepository.meta.json +7 -0
- package/lib/deps/capabilities.js +523 -0
- package/lib/deps/diff.js +84 -0
- package/lib/deps/index.js +416 -0
- package/lib/deps/lockfile.js +106 -0
- package/lib/deps/online.js +132 -0
- package/lib/deps/popular-packages.json +1 -0
- package/lib/deps/report.js +173 -0
- package/lib/deps/source.js +171 -0
- package/lib/deps/typosquat.js +113 -0
- package/lib/fix/apply.js +95 -0
- package/lib/fix/diff.js +199 -0
- package/lib/fix/index.js +129 -0
- package/lib/fix/model.js +108 -0
- package/lib/fix/recipes/cookies.js +130 -0
- package/lib/fix/recipes/cors.js +116 -0
- package/lib/fix/recipes/headers.js +250 -0
- package/lib/fix/recipes/rate-limit.js +211 -0
- package/lib/fix/recipes/secrets.js +110 -0
- package/lib/fix/util.js +231 -0
- package/lib/fuzzer.js +14 -8
- package/lib/injections.js +19 -15
- package/lib/install/index.js +271 -0
- package/lib/install/policy.js +117 -0
- package/lib/memory/history.js +52 -0
- package/lib/memory/index.js +111 -0
- package/lib/memory/repo-suppress.js +64 -0
- package/lib/memory/store.js +325 -0
- package/lib/memory/views.js +198 -0
- package/lib/params.js +4 -12
- package/lib/provenance.js +2 -0
- package/lib/recon.js +12 -20
- package/lib/references.js +31 -0
- package/lib/references.json +374 -0
- package/lib/remediation/index.js +28 -0
- package/lib/retirejs.js +50 -22
- package/lib/templates.js +7 -10
- package/lib/whitebox/frameworks.js +1 -1
- package/lib/whitebox/secrets.js +49 -19
- package/package.json +19 -9
- package/skills/penthera/SKILL.md +104 -23
- package/skills/penthera/references/output-and-ci.md +12 -50
- package/skills/penthera/references/troubleshooting.md +1 -1
- package/skills/penthera/scripts/preflight.sh +4 -4
- package/src/agent/git.js +87 -0
- package/src/agent/loop.js +519 -0
- package/src/agent/tests.js +48 -0
- package/src/cli/agent.js +183 -0
- package/src/cli/deps.js +84 -0
- package/src/cli/evidence.js +67 -0
- package/src/cli/fix.js +191 -0
- package/src/cli/install.js +225 -0
- package/src/cli/memory.js +146 -0
- package/src/cli/merge-results.js +2 -0
- package/src/cli/report-outputs.js +72 -0
- package/src/cli/run-scan.js +2 -0
- package/src/cli.js +152 -6
- package/src/report/audience.js +270 -0
- package/src/report/evidence.js +253 -0
- package/src/report/markdown.js +65 -2
- package/src/report/model.js +212 -0
- package/src/report/template.js +175 -0
- package/src/report/timeline.js +145 -0
- package/src/reporter.js +109 -5
- package/src/scan-url.js +31 -7
- package/src/utils/http.js +252 -11
- package/src/utils/url.js +23 -0
- package/scripts/package-skill.sh +0 -16
package/README.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="assets/penthera-social.jpg" alt="Penthera
|
|
3
|
+
<img src="assets/penthera-social.jpg" alt="Penthera: the routine work of a security team, on your own machine" width="840">
|
|
4
4
|
|
|
5
5
|
<br/><br/>
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/penthera)
|
|
8
|
-

|
|
9
9
|

|
|
10
10
|
[](https://github.com/danoszz/penthera/actions/workflows/ci.yml)
|
|
11
|
+
[](https://scorecard.dev/viewer/?uri=github.com/danoszz/penthera)
|
|
11
12
|
|
|
12
13
|
<br/>
|
|
13
14
|
|
|
@@ -17,14 +18,95 @@
|
|
|
17
18
|
|
|
18
19
|
---
|
|
19
20
|
|
|
21
|
+
<div align="center">
|
|
22
|
+
|
|
23
|
+
### The routine work of a security team, on your own machine.
|
|
24
|
+
|
|
25
|
+
**Penthera audits your app, your dependencies, and your AI tooling, fixes what it
|
|
26
|
+
can, proves the fix, and writes the evidence. Offline, deterministic, free, and
|
|
27
|
+
open source.**
|
|
28
|
+
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## What it does for you
|
|
34
|
+
|
|
35
|
+
Most small teams have no security engineer. Penthera covers the recurring work
|
|
36
|
+
one would do, from a CLI or from inside Claude Code and Cursor:
|
|
37
|
+
|
|
38
|
+
| The job | What Penthera does | Command |
|
|
39
|
+
|---------|--------------------|---------|
|
|
40
|
+
| **Test the app** | Black-box scan of a live URL (TLS, headers, CORS, auth, JWT, IDOR, OAuth, OpenAPI, opt-in injection and fuzzing) and white-box scan of the repo (routes, trust boundaries, secrets including AI provider keys) | `penthera <url> --repo .` |
|
|
41
|
+
| **Vet dependencies** | What every npm package can actually do (install scripts, shell, network, env, obfuscation), what an upgrade added, lookalike names | `penthera deps --base main` |
|
|
42
|
+
| **Guard installs** | Shows what a new package brings before any install script runs, and stops it under your policy | `penthera install <pkg>` |
|
|
43
|
+
| **Review pull requests** | Comments the dependency capability diff on every PR that touches the lockfile | [GitHub Action](#use-as-a-github-action) |
|
|
44
|
+
| **Audit your AI tooling** | Skills, MCP servers, hooks, plugins, and rule files: hidden instructions, unpinned servers, over-broad permissions, silent updates | `penthera agents --home` |
|
|
45
|
+
| **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` |
|
|
46
|
+
| **Report and prove** | Reports for developers, owners, and auditors; a hashed, signable evidence bundle; NIS2 readiness and incident drafts | `penthera <url> --audience auditor --evidence out/` |
|
|
47
|
+
|
|
48
|
+
What it is not: a human pentester, a 24/7 SOC, or incident response. It does the
|
|
49
|
+
repeatable checks so the people you do have can spend their time on judgement.
|
|
50
|
+
|
|
51
|
+
## Why you can trust it
|
|
52
|
+
|
|
53
|
+
- **Local and offline.** No account, no telemetry, no cloud. `--offline` limits
|
|
54
|
+
network traffic to the target you named, and every report lists the hosts that
|
|
55
|
+
were contacted.
|
|
56
|
+
- **Deterministic, not an AI verdict.** Rules you can read, with `file:line`
|
|
57
|
+
evidence and a confidence label on every finding. No model decides what is
|
|
58
|
+
malicious.
|
|
59
|
+
- **Never acts behind your back.** The fix loop works on a local branch, asks
|
|
60
|
+
before every change by default, and never pushes or opens pull requests.
|
|
61
|
+
- **No update channel to hijack.** Detection rules ship inside reviewed releases.
|
|
62
|
+
Nothing is downloaded and executed at run time.
|
|
63
|
+
- **Releases you can verify.** Published with npm provenance through trusted
|
|
64
|
+
publishing, and each version is approved by a maintainer with 2FA before it
|
|
65
|
+
goes live. SHA-pinned CI, CodeQL, and OpenSSF Scorecard.
|
|
66
|
+
- **Measured and cited.** A published [methodology](docs/METHODOLOGY.md),
|
|
67
|
+
[48 verified references](docs/references.md), and a reproducible
|
|
68
|
+
[benchmark](bench/RESULTS.md) with precision and recall.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## How Penthera fits with other tools
|
|
73
|
+
|
|
74
|
+
Penthera is meant to sit next to the tools you already use, not replace them.
|
|
75
|
+
Many teams run several of these together. Penthera's SARIF output goes straight
|
|
76
|
+
into GitHub code scanning, for example.
|
|
77
|
+
|
|
78
|
+
| | Focus | Where it runs | How it decides | Cost |
|
|
79
|
+
|---|---|---|---|---|
|
|
80
|
+
| **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 |
|
|
81
|
+
| [Socket](https://socket.dev) | 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 |
|
|
82
|
+
| [Snyk](https://snyk.io) | Known vulnerabilities in dependencies, code, containers, and IaC | Cloud service, IDE, CLI | Curated vulnerability database plus static analysis | Free tier and paid plans |
|
|
83
|
+
| [GitHub Dependabot and code scanning](https://docs.github.com/code-security) | Known-CVE alerts, update PRs, CodeQL | GitHub | Advisory database, CodeQL queries | Free for public repos |
|
|
84
|
+
| [OWASP ZAP](https://www.zaproxy.org) | Dynamic testing of web apps | Your machine or CI | Active and passive scan rules | Free, open source |
|
|
85
|
+
| [Anthropic OSS Scanner](https://red.anthropic.com/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 |
|
|
86
|
+
|
|
87
|
+
**Where Penthera adds something:**
|
|
88
|
+
- it checks your app, your dependencies and your AI agent setup in one tool;
|
|
89
|
+
- it runs entirely on your machine, with no account;
|
|
90
|
+
- it fixes what it finds and re-scans to verify the fix;
|
|
91
|
+
- it produces NIS2 evidence.
|
|
92
|
+
|
|
93
|
+
**Where others go further:** registry-wide package intelligence (Socket), curated
|
|
94
|
+
vulnerability data (Snyk, GitHub), and depth of dynamic testing (ZAP).
|
|
95
|
+
|
|
96
|
+
Descriptions reflect each project's public documentation as of October 2026.
|
|
97
|
+
Corrections are welcome by pull request.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
20
101
|
## Two ways to use it
|
|
21
102
|
|
|
22
|
-
**As an Agent Skill (recommended).**
|
|
23
|
-
|
|
24
|
-
|
|
103
|
+
**As an Agent Skill (recommended).** Let Claude Code or Cursor drive it:
|
|
104
|
+
[install once](#run-it), then ask it to "scan my app for security issues", "is
|
|
105
|
+
this package safe to add?", or "audit my MCP servers". The agent picks the
|
|
106
|
+
check, runs it, and walks you through the fixes.
|
|
25
107
|
|
|
26
|
-
**As a CLI.**
|
|
27
|
-
|
|
108
|
+
**As a CLI.** Run `penthera https://myapp.com`, or just `penthera` for the guided
|
|
109
|
+
wizard. See the [quick start](#quick-start).
|
|
28
110
|
|
|
29
111
|
---
|
|
30
112
|
|
|
@@ -32,13 +114,15 @@ issues." The agent picks the scan, runs it, and gives you the fixes.
|
|
|
32
114
|
|
|
33
115
|
You shipped something fast: vibecoded, AI-assisted, already live. The same models
|
|
34
116
|
that helped you build it also make it easy for someone to probe it. Exposed API
|
|
35
|
-
routes, missing security headers, weak auth, a hardcoded key in the repo
|
|
36
|
-
|
|
117
|
+
routes, missing security headers, weak auth, a hardcoded key in the repo, an AI
|
|
118
|
+
provider key in the frontend bundle. Meanwhile the packages, skills, and MCP
|
|
119
|
+
servers you pull in run with your credentials, and attackers know it: 2025 and
|
|
120
|
+
2026 brought self-spreading npm worms, malicious MCP servers, and poisoned agent
|
|
121
|
+
skills.
|
|
37
122
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
background to use it.
|
|
123
|
+
Commercial platforms answer this from the cloud, for a fee, often with an AI
|
|
124
|
+
judge deciding what is malicious. Penthera answers it on your machine, for free,
|
|
125
|
+
with rules you can read.
|
|
42
126
|
|
|
43
127
|
Penthera is for hardening systems you own. It is powerful, so please use it
|
|
44
128
|
carefully. See [Ethical use](#ethical-use--authorization) and the [Disclaimer](#disclaimer).
|
|
@@ -46,7 +130,7 @@ carefully. See [Ethical use](#ethical-use--authorization) and the [Disclaimer](#
|
|
|
46
130
|
Shipping in the EU? Penthera also generates your
|
|
47
131
|
[NIS2 readiness report, policy pack, incident-report drafts, SBOM, and prefilled
|
|
48
132
|
customer security questionnaires](#compliance-nis2-and-the-cyberwetgeving).
|
|
49
|
-
|
|
133
|
+
Readiness tooling, not a certification.
|
|
50
134
|
|
|
51
135
|
### What you get
|
|
52
136
|
|
|
@@ -73,6 +157,8 @@ out as Markdown, JSON, and SARIF, with the fixes in priority order.
|
|
|
73
157
|
|
|
74
158
|
---
|
|
75
159
|
|
|
160
|
+
---
|
|
161
|
+
|
|
76
162
|
## Run it
|
|
77
163
|
|
|
78
164
|
**One-line install** (clones the repo, links the CLI, and installs the skill into
|
|
@@ -109,15 +195,16 @@ Prefer the terminal? Run `penthera` with no arguments for a guided wizard.
|
|
|
109
195
|
|
|
110
196
|
---
|
|
111
197
|
|
|
112
|
-
##
|
|
198
|
+
## Scan modes and profiles
|
|
113
199
|
|
|
114
200
|
| Mode | Command | Coverage |
|
|
115
201
|
|------|---------|----------|
|
|
116
202
|
| **URL scan** | `penthera https://example.com` | TLS, fingerprinting, endpoint discovery, templates, CORS, cookies, JS CVEs, param discovery, OpenAPI/FastAPI probes, security headers, auth hardening |
|
|
117
|
-
| **Repo scan** | `penthera --repo ./my-app` | API route discovery (Next.js, Express, Hono, Fastify), trust-boundary mapping, hardcoded-secret scanning |
|
|
203
|
+
| **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) |
|
|
118
204
|
| **Combined** | `penthera https://staging.app --repo .` | Black-box and white-box in one run |
|
|
119
205
|
| **Interactive** | `penthera` *(no args)* | Guided wizard (URL plus optional repo scan, Markdown report) |
|
|
120
206
|
| **Machine audit** | `penthera --machine` | macOS checks (keyloggers, persistence, rootkits) |
|
|
207
|
+
| **Dependencies** | `penthera deps` | What each npm package can do (install scripts, shell, network, env, eval, native, obfuscation), capability diff on upgrades, typosquats. Offline |
|
|
121
208
|
|
|
122
209
|
Pick a profile, or add individual flags for more depth:
|
|
123
210
|
|
|
@@ -135,264 +222,26 @@ Individual flags: `--recon`, `--deep`, `--fuzz`, `--adaptive`, `--nuclei <path>`
|
|
|
135
222
|
|
|
136
223
|
```mermaid
|
|
137
224
|
flowchart LR
|
|
138
|
-
U["You / your AI agent"]
|
|
225
|
+
U["You / your AI agent"] --> P((Penthera))
|
|
139
226
|
|
|
140
|
-
P -->
|
|
141
|
-
P -->
|
|
142
|
-
P -->
|
|
227
|
+
P --> APP["Your app<br/>black-box URL scan<br/>white-box repo scan"]
|
|
228
|
+
P --> DEP["Your dependencies<br/>capabilities, upgrade diff<br/>install firewall, typosquats"]
|
|
229
|
+
P --> AI["Your AI tooling<br/>skills, MCP, hooks<br/>plugins, rule files"]
|
|
143
230
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
231
|
+
APP --> F[["Findings<br/>severity, confidence<br/>evidence, sources"]]
|
|
232
|
+
DEP --> F
|
|
233
|
+
AI --> F
|
|
147
234
|
|
|
148
|
-
F -->
|
|
149
|
-
|
|
150
|
-
F -->
|
|
151
|
-
F -->
|
|
235
|
+
F --> FIX["Fix loop<br/>local branch, re-scan<br/>learn, never push"]
|
|
236
|
+
FIX -.verified.-> F
|
|
237
|
+
F --> R["Reports<br/>terminal, Markdown, JSON<br/>SARIF, audience views"]
|
|
238
|
+
F --> E["Evidence<br/>hashed, signable bundle<br/>NIS2 readiness"]
|
|
152
239
|
```
|
|
153
240
|
|
|
154
241
|
Findings map to the [OWASP Web Security Testing Guide](docs/owasp-wstg-coverage.md)
|
|
155
|
-
(WSTG v4.2)
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
---
|
|
159
|
-
|
|
160
|
-
## Compliance: NIS2 and the cyberwetgeving
|
|
161
|
-
|
|
162
|
-
The EU NIS2 directive and its national transpositions (the Cyberbeveiligingswet
|
|
163
|
-
in the Netherlands, the NIS2-wet in Belgium) put a duty of care, the *zorgplicht*,
|
|
164
|
-
on in-scope organisations. That duty is the set of risk-management measures in
|
|
165
|
-
Article 21(2) of the directive. Most of them are organisational. Some are
|
|
166
|
-
technical and testable, and that is the part Penthera helps with.
|
|
167
|
-
|
|
168
|
-
Penthera does not make you compliant and does not certify anything. What it gives
|
|
169
|
-
you is automated, repeatable technical evidence for the measures a scanner can
|
|
170
|
-
honestly verify: the kind of artefact you can attach to a risk file, show an
|
|
171
|
-
auditor, or run in CI so a regression shows up before it ships.
|
|
172
|
-
|
|
173
|
-
| Art. 21(2) measure | What Penthera does | Coverage |
|
|
174
|
-
|--------------------|--------------------|----------|
|
|
175
|
-
| **(a)** Risk analysis & information-security policy | Findings, severity, and baseline history feed your risk analysis | Evidence |
|
|
176
|
-
| **(b)** Incident handling | `--incident` drafts the 24h / 72h / 1-month reports against your authority's required content | Partial |
|
|
177
|
-
| **(c)** Business continuity, backup, crisis management | Organisational; outside a scanner's reach | Out of scope |
|
|
178
|
-
| **(d)** Supply-chain security | Known-CVE checks on JS dependencies, leaked credentials, a CycloneDX SBOM (`--sbom`), and passive supplier rating (`--suppliers`) | Partial |
|
|
179
|
-
| **(e)** Security in acquisition, development & maintenance; **vulnerability handling** | The core: black- + white-box scanning mapped to OWASP WSTG, SARIF → GitHub, baseline regression, scan-and-fix loop | **Strong** |
|
|
180
|
-
| **(f)** Assessing the effectiveness of measures | Baseline diff, re-scan-to-verify, and `--history` tracking of time-to-fix, ageing, and drift | Partial |
|
|
181
|
-
| **(g)** Cyber hygiene & training | Remediation playbook + secure-defaults guidance (guidance, not a training programme) | Partial |
|
|
182
|
-
| **(h)** Cryptography & encryption | TLS protocol/cipher/certificate audit, HSTS, cookie `Secure` (transport layer only) | Partial |
|
|
183
|
-
| **(i)** HR security, **access control**, asset management | Access control tested: JWT, IDOR/BOLA, OAuth redirect, client-side-auth, trust-boundary mapping | Partial |
|
|
184
|
-
| **(j)** Multi-factor authentication & secure communications | MFA probe (on the roadmap) | Planned |
|
|
185
|
-
|
|
186
|
-
**Coverage key:** *Strong* = automated technical testing · *Partial* = part of the
|
|
187
|
-
measure · *Evidence* = output feeds the measure, no direct test · *Planned* = on the
|
|
188
|
-
roadmap · *Out of scope* = organisational or physical.
|
|
189
|
-
|
|
190
|
-
In practice, Penthera today gives you solid automated evidence for the
|
|
191
|
-
secure-development and vulnerability-handling duty (e), which is the technical
|
|
192
|
-
heart of the zorgplicht, plus meaningful coverage of supply chain (d),
|
|
193
|
-
cryptography in transit (h), access control (i), and effectiveness testing (f).
|
|
194
|
-
That is not the whole duty of care, but it is a real, defensible start you can run
|
|
195
|
-
today and re-run on every deploy.
|
|
196
|
-
|
|
197
|
-
> **Not legal advice, not a certification, not a guarantee of compliance.**
|
|
198
|
-
> Penthera automates the technical-testing part of the duty of care. The
|
|
199
|
-
> directive's organisational duties (governance, risk-management policy,
|
|
200
|
-
> incident-notification processes, supply-chain contracts, staff training) need
|
|
201
|
-
> human process and, where it matters, review by a qualified advisor. For an
|
|
202
|
-
> authoritative reading, consult your national authority (the NCSC in the
|
|
203
|
-
> Netherlands, the CCB and its CyFun framework in Belgium) or a specialised jurist.
|
|
204
|
-
|
|
205
|
-
Generate this mapping for your own scan with `--framework nis2`. It adds a
|
|
206
|
-
per-run coverage table (which measures *this* scan actually exercised, driven by
|
|
207
|
-
the probes that ran) to the terminal, Markdown, and JSON reports:
|
|
208
|
-
|
|
209
|
-
```bash
|
|
210
|
-
penthera https://myapp.com --framework nis2 -o reports/scan.json
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
### Readiness report (clone → report in two commands)
|
|
214
|
-
|
|
215
|
-
Go further than the mapping: combine the scan with a short offline
|
|
216
|
-
self-assessment (the organisational measures a scanner can't test, like policies,
|
|
217
|
-
backups, training, and MFA) into a full NIS2 readiness report. Every Article 21
|
|
218
|
-
measure is marked `met / partial / gap / n-a`, with proportionality notes, your
|
|
219
|
-
incident-reporting deadlines, and provenance on every piece of evidence.
|
|
220
|
-
|
|
221
|
-
```bash
|
|
222
|
-
# 1. Create your self-assessment (offline, one-time). Fill in yes | partial | no | na.
|
|
223
|
-
penthera --assessment-init assessment.json
|
|
224
|
-
|
|
225
|
-
# 2. Scan + self-assessment → readiness report (writes reports/scan-readiness.md)
|
|
226
|
-
penthera https://myapp.com --repo . --readiness --assessment assessment.json -o reports/scan.json
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
The readiness report is **evidence and self-assessment tooling, not a
|
|
230
|
-
certification**. It is provenance-linked (`source, method, collected_at,
|
|
231
|
-
confidence`) and reproducible, and it lists exactly what only you can attest to.
|
|
232
|
-
Jurisdiction specifics live in `lib/jurisdictions/nl.json` (NL today; BE and
|
|
233
|
-
others are just added config).
|
|
234
|
-
|
|
235
|
-
### Answer a customer's security questionnaire
|
|
236
|
-
|
|
237
|
-
The questionnaire blocking your deal, drafted from evidence you already have:
|
|
238
|
-
|
|
239
|
-
```bash
|
|
240
|
-
# one question per line, pasted from the customer's form
|
|
241
|
-
penthera https://myapp.com --readiness --assessment assessment.json --questionnaire questions.txt
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
Each question is mapped to the Article 21 measure it belongs to and answered
|
|
245
|
-
from the scan and your self-assessment, with the backing evidence cited.
|
|
246
|
-
Anything Penthera can't map is marked `NEEDS HUMAN INPUT` instead of guessed.
|
|
247
|
-
Review every answer before you send it.
|
|
248
|
-
|
|
249
|
-
### Policy pack
|
|
250
|
-
|
|
251
|
-
Generate the proportionate written policies NIS2 expects, pre-filled from your
|
|
252
|
-
readiness gaps and the NL incident deadlines:
|
|
253
|
-
|
|
254
|
-
```bash
|
|
255
|
-
penthera --policy-pack ./policies --org "Your Company" --readiness --assessment assessment.json
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
Writes editable Markdown starting points: information security, access control,
|
|
259
|
-
incident response, backup/continuity, acceptable use, supplier security, and
|
|
260
|
-
vulnerability management. **Templates, not legal advice.** Keep them short and
|
|
261
|
-
used. A two-page policy that genuinely exists is what "proportionate" means.
|
|
262
|
-
|
|
263
|
-
### Incident-report helper
|
|
264
|
-
|
|
265
|
-
NIS2 has hard reporting deadlines (24h early warning, 72h notification, 1-month
|
|
266
|
-
final report). If something happens, get the timeline and draft reports:
|
|
267
|
-
|
|
268
|
-
```bash
|
|
269
|
-
penthera --incident-init incident.json # fill in what happened (set aware_at)
|
|
270
|
-
penthera --incident incident.json # writes incident-reports.md
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
It computes your three deadlines from when you became aware, flags anything
|
|
274
|
-
overdue, and drafts the early-warning, notification, and final report against
|
|
275
|
-
the required content, with `NEEDS INPUT` where you still have to fill in facts.
|
|
276
|
-
**These are drafts to help you meet the deadlines, not a substitute for your
|
|
277
|
-
authority's official form.**
|
|
278
|
-
|
|
279
|
-
### Software bill of materials (SBOM)
|
|
280
|
-
|
|
281
|
-
Emit a standard CycloneDX SBOM of your dependencies. It's what enterprises
|
|
282
|
-
increasingly require of suppliers, and direct evidence for supply-chain security
|
|
283
|
-
(measure d):
|
|
284
|
-
|
|
285
|
-
```bash
|
|
286
|
-
penthera --repo . --sbom sbom.cdx.json
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
Parses `package-lock.json` / `package.json` / `requirements.txt` offline (no
|
|
290
|
-
network), with resolved versions and package URLs (purls).
|
|
291
|
-
|
|
292
|
-
### Remediation tracking (the audit loop)
|
|
293
|
-
|
|
294
|
-
Closing findings matters more than finding them. Track them over time:
|
|
295
|
-
time-to-fix, ageing of open items, and what changed since the last scan (evidence
|
|
296
|
-
for measure f, effectiveness):
|
|
297
|
-
|
|
298
|
-
```bash
|
|
299
|
-
penthera https://myapp.com --history reports/history.json -o reports/scan.json
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
Each run folds the current findings into a small history keyed by a **stable
|
|
303
|
-
fingerprint** (so a re-worded or re-counted finding isn't mistaken for a new
|
|
304
|
-
one), then reports open vs resolved, median time-to-fix, and ageing buckets.
|
|
305
|
-
Re-run on a cadence to watch the trend.
|
|
306
|
-
|
|
307
|
-
### Supplier rating (passive)
|
|
308
|
-
|
|
309
|
-
Assess your suppliers' public security posture for supply-chain risk (measure d):
|
|
310
|
-
|
|
311
|
-
```bash
|
|
312
|
-
printf 'supplier1.com\nsupplier2.com\n' > suppliers.txt
|
|
313
|
-
penthera --suppliers suppliers.txt
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
**Strictly passive and public-data-only.** One homepage GET (security headers),
|
|
317
|
-
a TLS handshake (certificate), and public DNS lookups (SPF/DMARC/MX) per domain.
|
|
318
|
-
No endpoint discovery, no auth probes, no intrusive testing. You get a
|
|
319
|
-
red/amber/green rating per supplier. It's a screening aid for your own vendor
|
|
320
|
-
risk assessment, **not** an authorised penetration test of the supplier.
|
|
321
|
-
|
|
322
|
-
Because the mapping targets the NIS2 directive itself, it applies across the
|
|
323
|
-
national transpositions; jurisdiction-specific profiles (NL, BE) are on the roadmap.
|
|
324
|
-
|
|
325
|
-
---
|
|
326
|
-
|
|
327
|
-
## Ethical use & authorization
|
|
328
|
-
|
|
329
|
-
Penthera sends HTTP requests to the targets you give it. Some modes (`--deep`,
|
|
330
|
-
`--fuzz`, `--all`) send attack payloads designed to find vulnerabilities. Use it
|
|
331
|
-
responsibly.
|
|
332
|
-
|
|
333
|
-
**You may use Penthera when:**
|
|
334
|
-
|
|
335
|
-
- You **own** the target (your app, your server, your project).
|
|
336
|
-
- You have **written authorization** from the system owner (email, ticket, signed scope).
|
|
337
|
-
- You scan **localhost** or private lab environments you control.
|
|
338
|
-
- You use it for **defensive security**: research, coursework, CI hardening, pre-release audits.
|
|
339
|
-
|
|
340
|
-
**You must not use Penthera to:**
|
|
341
|
-
|
|
342
|
-
- Scan systems you do not own or lack explicit permission to test.
|
|
343
|
-
- Probe government, healthcare, financial, or third-party production systems without authorization.
|
|
344
|
-
- Exfiltrate data, disrupt services, or bypass access controls.
|
|
345
|
-
- Use findings to attack, extort, or harm anyone.
|
|
346
|
-
|
|
347
|
-
> Before scanning any URL that is not localhost, confirm you have permission.
|
|
348
|
-
> **When in doubt, do not scan.**
|
|
349
|
-
|
|
350
|
-
Unauthorized security testing may violate computer-misuse laws (for example the US
|
|
351
|
-
CFAA, the UK Computer Misuse Act, and EU national equivalents) and can result in
|
|
352
|
-
criminal prosecution, civil liability, IP blocking, account termination, and
|
|
353
|
-
academic or professional penalties.
|
|
354
|
-
|
|
355
|
-
---
|
|
356
|
-
|
|
357
|
-
## Disclaimer
|
|
358
|
-
|
|
359
|
-
Penthera is provided for legitimate security research and defensive testing of
|
|
360
|
-
systems you own or are authorized to test, and for that purpose only.
|
|
361
|
-
|
|
362
|
-
- It is a research and self-assessment tool. Scan your own apps to find and fix
|
|
363
|
-
weaknesses before attackers do.
|
|
364
|
-
- The same capabilities that harden a system can cause harm if pointed at someone
|
|
365
|
-
else's. Use it carefully and lawfully.
|
|
366
|
-
- The author does not condone unauthorized or malicious use, and accepts no
|
|
367
|
-
liability for any damage, loss, or legal consequence arising from use or misuse
|
|
368
|
-
of this software.
|
|
369
|
-
- The software is provided "as is", without warranty of any kind. See [LICENSE](LICENSE) (MIT).
|
|
370
|
-
- You are solely responsible for ensuring every scan you run is authorized and
|
|
371
|
-
legal in your jurisdiction.
|
|
372
|
-
|
|
373
|
-
By using Penthera you accept these terms.
|
|
374
|
-
|
|
375
|
-
---
|
|
376
|
-
|
|
377
|
-
## Install
|
|
378
|
-
|
|
379
|
-
The [one-line installer](#run-it) is the fastest path. To set it up manually:
|
|
380
|
-
|
|
381
|
-
```bash
|
|
382
|
-
git clone https://github.com/danoszz/penthera.git
|
|
383
|
-
cd penthera
|
|
384
|
-
npm install
|
|
385
|
-
npm link # exposes `penthera` and `penthera-scan` globally
|
|
386
|
-
penthera --version
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
Requirements: Node.js 18+ and npm. Optional: nuclei-templates for `--nuclei`, and
|
|
390
|
-
Docker. To run it in a container:
|
|
391
|
-
|
|
392
|
-
```bash
|
|
393
|
-
docker build -t penthera .
|
|
394
|
-
docker run --rm penthera https://your-app.example
|
|
395
|
-
```
|
|
242
|
+
(WSTG v4.2), and agent findings to the OWASP MCP and Agentic Top 10s. The
|
|
243
|
+
default scan is non-destructive. Payload-based testing is opt-in (`--deep`,
|
|
244
|
+
`--fuzz`, `--all`) and gated behind explicit confirmation.
|
|
396
245
|
|
|
397
246
|
---
|
|
398
247
|
|
|
@@ -437,6 +286,9 @@ next to it. Reports are gitignored by default.
|
|
|
437
286
|
| **Markdown** | `--markdown file.md` or `-o file.json` | Human-readable report (exec summary, findings tables, fixes). Written next to `-o` automatically |
|
|
438
287
|
| JSON | `--json` or `-o file.json` | CI pipelines, baseline diffs, custom tooling |
|
|
439
288
|
| SARIF | `--sarif file.sarif` | GitHub Security / Code Scanning tab |
|
|
289
|
+
| Audience report | `--audience developer\|owner\|auditor` | The same scan written for a developer, an owner or an auditor ([docs/evidence.md](docs/evidence.md#audience-reports)) |
|
|
290
|
+
| Your template | `--report-template file.md` | Your own Markdown with `{{summary.critical}}`, `{{#each findings}}`, `{{#if x}}`; no code runs |
|
|
291
|
+
| **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](docs/evidence.md)) |
|
|
440
292
|
|
|
441
293
|
---
|
|
442
294
|
|
|
@@ -481,6 +333,7 @@ npm run package:skill # produces penthera-skill.zip; upload in Settings > Capa
|
|
|
481
333
|
- "Scan this repo for hardcoded secrets and exposed API routes"
|
|
482
334
|
- "Compare today's scan to last week's baseline and show only new findings"
|
|
483
335
|
- "Generate a SARIF report for GitHub code scanning"
|
|
336
|
+
- "Audit my MCP servers, skills and Claude Code hooks"
|
|
484
337
|
|
|
485
338
|
The skill adds an authorization gate: it instructs the agent to refuse targets you
|
|
486
339
|
do not own or are not authorized to test, and the wizard asks you to confirm before
|
|
@@ -496,6 +349,43 @@ Skill source and workflows live in [`skills/penthera/SKILL.md`](skills/penthera/
|
|
|
496
349
|
|
|
497
350
|
---
|
|
498
351
|
|
|
352
|
+
## Audit your agent setup
|
|
353
|
+
|
|
354
|
+
Your AI tools run code too. `penthera agents` audits the skills, MCP servers,
|
|
355
|
+
hooks, permissions, plugins and rule files that Claude Code, Cursor, Claude
|
|
356
|
+
Desktop, VS Code and Copilot load, and grades the setup A to F.
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
penthera agents # this repo: .mcp.json, .claude/, .cursor/, AGENTS.md, CLAUDE.md, skills/
|
|
360
|
+
penthera agents --home # + ~/.claude (hooks, permissions, plugins, skills), ~/.cursor/mcp.json, Claude Desktop
|
|
361
|
+
penthera agents ./some-skill # vet a downloaded skill before you install it
|
|
362
|
+
penthera agents --pin # write penthera.lock; later runs flag anything that changed
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
It is **offline and deterministic**: no LLM judge, no registry lookups, nothing
|
|
366
|
+
leaves your machine, and it never modifies the config it reads. Every verdict
|
|
367
|
+
is a rule you can read in [`lib/agents/`](lib/agents/), so a skill can't talk
|
|
368
|
+
its way past it.
|
|
369
|
+
|
|
370
|
+
| Check | What it catches |
|
|
371
|
+
|---|---|
|
|
372
|
+
| 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 |
|
|
373
|
+
| 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 |
|
|
374
|
+
| 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://` |
|
|
375
|
+
| 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` |
|
|
376
|
+
| Plugins | Marketplaces and marketplace plugins not pinned to a commit |
|
|
377
|
+
| 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 |
|
|
378
|
+
|
|
379
|
+
Each finding names the OWASP [MCP Top 10](https://owasp.org/www-project-mcp-top-10/)
|
|
380
|
+
and [Agentic Top 10](https://genai.owasp.org/) (ASI) ids it maps to, and the
|
|
381
|
+
usual `--json`, `-o`, `--markdown` and `--sarif` outputs all work. The scanner
|
|
382
|
+
is built for the ways LLM-judged skill scanners have been bypassed: it reads
|
|
383
|
+
whole files (no context window to overflow), every file in a skill folder (not
|
|
384
|
+
just `SKILL.md`), and treats text aimed at a reviewer as a finding rather than
|
|
385
|
+
an argument.
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
499
389
|
## Scan and fix
|
|
500
390
|
|
|
501
391
|
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.
|
|
@@ -508,21 +398,256 @@ Penthera does not just report problems. It closes the loop: ask your agent to fi
|
|
|
508
398
|
|
|
509
399
|
Fixes come from a [remediation playbook](skills/penthera/references/remediation.md) 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](skills/penthera/references/secure-defaults.md).
|
|
510
400
|
|
|
401
|
+
### Fix recipes
|
|
402
|
+
|
|
403
|
+
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:
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
penthera fix --plan --repo . # fresh repo scan, one diff per fix
|
|
407
|
+
penthera fix --plan --repo . -o report.json # or use the findings from an earlier scan
|
|
408
|
+
penthera fix --apply <id> --repo . # apply one diff after you approve it
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
| Recipe | What it changes | Frameworks |
|
|
412
|
+
|--------|-----------------|------------|
|
|
413
|
+
| `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`) |
|
|
414
|
+
| `cookie-flags` | Adds `httpOnly`, `secure` and `sameSite` to cookies set in code | `res.cookie`, `reply.setCookie`, Hono `setCookie`, Next.js `cookies().set` |
|
|
415
|
+
| `cors-allowlist` | Replaces `cors()`, `origin: "*"`, `origin: true` and `origin \|\| "*"` with an allowlist from `CORS_ALLOWED_ORIGINS` | Express, Fastify, Hono, Next.js route handlers |
|
|
416
|
+
| `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 |
|
|
417
|
+
| `secret-to-env` | Moves a hardcoded secret in JS/TS to `process.env.NAME` and adds `NAME=` to `.env.example` | Any |
|
|
418
|
+
|
|
419
|
+
How it stays safe:
|
|
420
|
+
|
|
421
|
+
- **Planning never writes.** Applying is a separate step: it needs a plan id plus a `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.
|
|
422
|
+
- **Conservative edits.** No AST rewriting: each recipe edits at an anchor it recognises exactly (`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.
|
|
423
|
+
- **Owner actions are listed, not done.** A recipe can move a secret out of the code but can never rotate it, so every secret fix says "rotate this secret". Other recipes flag what is still on you, such as tightening the starter CSP or setting `CORS_ALLOWED_ORIGINS`.
|
|
424
|
+
- **Secrets stay masked.** The secret's value is masked in printed and `--json` plans.
|
|
425
|
+
- **Verified.** After `--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.
|
|
426
|
+
|
|
427
|
+
No recipe for a finding? `--fix-model <name>` can ask a model running in [Ollama](https://ollama.com) 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`.
|
|
428
|
+
|
|
429
|
+
### The local loop: `penthera agent --loop`
|
|
430
|
+
|
|
431
|
+
`penthera agent --loop` runs scan → fix → verify → learn on your machine until nothing fixable is left (or `--max-iterations`, default 5):
|
|
432
|
+
|
|
433
|
+
```bash
|
|
434
|
+
penthera agent --loop --repo . --url http://localhost:3000 -o reports/loop.json
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
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](docs/local-loop.md). 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](docs/local-loop.md#the-agent-loop).
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## Dependency risk: what can your packages do?
|
|
442
|
+
|
|
443
|
+
A lockfile change is code you did not write, about to run with your app's access
|
|
444
|
+
to files, network, environment and CI secrets. `penthera deps` reads
|
|
445
|
+
`package-lock.json`, statically scans every installed package, and tells you
|
|
446
|
+
what each one *can do*, and which packages are new or gained capabilities in an
|
|
447
|
+
upgrade.
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
penthera deps # every package in node_modules
|
|
451
|
+
penthera deps --base origin/main # capability diff vs the lockfile on main
|
|
452
|
+
penthera deps --diff ../base-checkout # diff vs another installed tree (or an old package-lock.json)
|
|
453
|
+
penthera deps --pr-comment deps.md # short Markdown diff for a PR comment
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
```
|
|
457
|
+
▲ net-helper 1.0.0 → 1.1.0 + network, whole environment
|
|
458
|
+
node_modules/net-helper/index.js:3 const https = require('https');
|
|
459
|
+
node_modules/net-helper/index.js:5 const body = JSON.stringify(process.env);
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
| Capability | Detected from |
|
|
463
|
+
|---|---|
|
|
464
|
+
| 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 |
|
|
465
|
+
| Shell, network, dynamic code | `child_process`; `http`/`https`/`net`/`dgram`/`tls`/`http2`, `fetch`, `WebSocket`; `eval`, `new Function`, `vm` |
|
|
466
|
+
| Environment | `process.env` reads, and bulk access (`JSON.stringify(process.env)`, enumeration). Serialising the environment next to network code is reported as likely exfiltration |
|
|
467
|
+
| Files, modules, native | Writes near home-directory or system paths; computed `require()`/`import()`; `.node` addons and `binding.gyp` |
|
|
468
|
+
| Obfuscation | Obfuscator identifiers (`_0x…`), `\x`-escape density, encoded blobs that are decoded and run (embedded WebAssembly and ANSI colour codes are recognised and ignored) |
|
|
469
|
+
| 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 |
|
|
470
|
+
| Typosquats | Edit distance, separator and suffix tricks against ~7,800 popular npm names, vendored in the package and refreshed at release time |
|
|
471
|
+
|
|
472
|
+
Every capability carries `file:line` evidence. It is a regex-and-tokenizer pass,
|
|
473
|
+
not a full parser: deterministic, never executes package code, and fast enough
|
|
474
|
+
for every PR (0.4 s for Penthera's own 61 packages, 5 to 16 s for real app
|
|
475
|
+
trees of 500 to 1,700 packages). A capability is what code
|
|
476
|
+
*can* do, not proof that it is malicious; the findings carry honest confidence
|
|
477
|
+
labels (`potential` for obfuscation and typosquats).
|
|
478
|
+
|
|
479
|
+
**Offline by default.** Old versions for the diff come from the base tree's
|
|
480
|
+
`node_modules` or from npm's local cache (`~/.npm/_cacache`), looked up by the
|
|
481
|
+
lockfile's integrity hash and verified byte for byte. `--online` is the only
|
|
482
|
+
network use: it asks the npm registry for publish dates, publisher changes and
|
|
483
|
+
deprecations, and fetches old tarballs the cache does not have (verified the
|
|
484
|
+
same way). To comment the capability diff on every PR that changes the
|
|
485
|
+
lockfile, use the GitHub Action below.
|
|
486
|
+
|
|
487
|
+
### Use as a GitHub Action
|
|
488
|
+
|
|
489
|
+
```yaml
|
|
490
|
+
- uses: danoszz/penthera@<release-commit-sha> # v1.4.0
|
|
491
|
+
with:
|
|
492
|
+
mode: deps # deps | agents | scan (scan also needs url:)
|
|
493
|
+
fail-on: none # none | high | critical
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
On every pull request it posts one comment with the capability diff against
|
|
497
|
+
the PR base and edits that same comment on each push. It also uploads SARIF to
|
|
498
|
+
code scanning. Penthera runs from the action's own checkout: no npx, no install
|
|
499
|
+
from npm, no registry lookups. On fork PRs the token is read-only, so the diff
|
|
500
|
+
goes to the job summary instead. Inputs: `mode`, `path`, `base-ref`, `url`,
|
|
501
|
+
`fail-on`, `comment`, `sarif`, `penthera-version`. Copy the full workflow, with
|
|
502
|
+
permissions and a lockfile paths filter, from
|
|
503
|
+
[`docs/examples/pr-dependency-review.yml`](docs/examples/pr-dependency-review.yml).
|
|
504
|
+
|
|
505
|
+
### Install firewall: `penthera install`
|
|
506
|
+
|
|
507
|
+
`penthera deps` tells you what changed after the fact. `penthera install` asks
|
|
508
|
+
before anything runs:
|
|
509
|
+
|
|
510
|
+
```bash
|
|
511
|
+
penthera install left-pad # check, then install (asks if the policy says so)
|
|
512
|
+
penthera install -D vitest --dry-run # report only
|
|
513
|
+
penthera install --yes # CI: install only if nothing breaches the policy
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
```
|
|
517
|
+
▲ color-helper 1.0.0 → 1.1.0 + install script
|
|
518
|
+
postinstall: node postinstall.js
|
|
519
|
+
|
|
520
|
+
Policy defaults (no penthera.policy.json)
|
|
521
|
+
! color-helper@1.1.0 needs approval: install script
|
|
522
|
+
|
|
523
|
+
Install anyway? [y]es, run the install scripts / [s]kip scripts / [N]o:
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
1. npm resolves the new tree in a temporary copy of `package.json` and the
|
|
527
|
+
lockfile, with scripts off (`npm install --package-lock-only --ignore-scripts`).
|
|
528
|
+
2. New tarballs are fetched with `npm cache add`. Nothing is unpacked into
|
|
529
|
+
`node_modules` and no package code runs; each tarball is checked against
|
|
530
|
+
the proposed lockfile's integrity before it is read.
|
|
531
|
+
3. The `deps` engine diffs capabilities against your current lockfile, lists
|
|
532
|
+
new install scripts with their commands, and checks new names for typosquats.
|
|
533
|
+
4. `penthera.policy.json` decides. On approval, the reviewed lockfile is
|
|
534
|
+
installed as is, with `--ignore-scripts` unless you approved the scripts
|
|
535
|
+
(on npm 12+, approved scripts are pinned in `package.json` `allowScripts`).
|
|
536
|
+
On abort, exit code 1, and the project is byte for byte unchanged.
|
|
537
|
+
|
|
538
|
+
```json
|
|
539
|
+
{
|
|
540
|
+
"allow": ["@acme/*", "esbuild", "sharp@0.33.5"],
|
|
541
|
+
"deny": ["ai-cli-invoke", "token-harvest"],
|
|
542
|
+
"requireApproval": ["install-scripts", "ai-config-write", "ai-cli-invoke",
|
|
543
|
+
"token-harvest", "obfuscated", "typosquat", "unscanned"]
|
|
544
|
+
}
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
`deny` and `requireApproval` take capability ids from the table above
|
|
548
|
+
(`install-scripts`, `shell`, `network`, `env-bulk`, `obfuscated`, ...) plus
|
|
549
|
+
`typosquat` and `unscanned`. The `requireApproval` list shown is the default.
|
|
550
|
+
`allow` takes names or globs, optionally pinned to a version, and overrides
|
|
551
|
+
both. The one network use is npm talking to your configured registry, and
|
|
552
|
+
Penthera prints which one; Penthera itself sends nothing. Workspaces and
|
|
553
|
+
`file:` dependencies are not supported yet.
|
|
554
|
+
|
|
555
|
+
---
|
|
556
|
+
|
|
557
|
+
## Compliance: NIS2 and the cyberwetgeving
|
|
558
|
+
|
|
559
|
+
Shipping in the EU? NIS2 (the Cyberbeveiligingswet in the Netherlands, the
|
|
560
|
+
NIS2-wet in Belgium) puts a duty of care on in-scope organisations. Penthera
|
|
561
|
+
turns the technical, testable part of that duty into repeatable evidence, and
|
|
562
|
+
helps with the paperwork around it. Offline, no accounts.
|
|
563
|
+
|
|
564
|
+
| Command | What you get |
|
|
565
|
+
|---------|--------------|
|
|
566
|
+
| `--framework nis2` | Per-run Article 21(2) coverage table in every report |
|
|
567
|
+
| `--readiness --assessment a.json` | Full readiness report: every measure marked met / partial / gap |
|
|
568
|
+
| `--questionnaire questions.txt` | Customer security questionnaire drafted from your evidence |
|
|
569
|
+
| `--policy-pack ./policies` | Proportionate policy templates, prefilled from your gaps |
|
|
570
|
+
| `--incident incident.json` | 24h / 72h / 1-month incident report drafts and deadlines |
|
|
571
|
+
| `--sbom sbom.cdx.json` | CycloneDX software bill of materials |
|
|
572
|
+
| `--history history.json` | Time-to-fix, ageing, and drift across scans |
|
|
573
|
+
| `--suppliers suppliers.txt` | Passive red/amber/green rating of your suppliers |
|
|
574
|
+
|
|
575
|
+
**Full guide, the measure-by-measure coverage table, and the limits:**
|
|
576
|
+
[docs/compliance-nis2.md](docs/compliance-nis2.md).
|
|
577
|
+
|
|
578
|
+
> Readiness tooling, not a certification and not legal advice.
|
|
579
|
+
|
|
511
580
|
---
|
|
512
581
|
|
|
513
582
|
## CI integration
|
|
514
583
|
|
|
515
584
|
```yaml
|
|
516
585
|
# Scan a staging URL on a schedule and upload results to GitHub Security.
|
|
517
|
-
|
|
518
|
-
-
|
|
519
|
-
- uses: github/codeql-action/upload-sarif@v3
|
|
586
|
+
- run: npx penthera@1.4.0 "$PENTEST_URL" --profile standard --sarif reports/scan.sarif
|
|
587
|
+
- uses: github/codeql-action/upload-sarif@v4
|
|
520
588
|
with:
|
|
521
589
|
sarif_file: reports/scan.sarif
|
|
522
590
|
```
|
|
523
591
|
|
|
524
|
-
|
|
525
|
-
|
|
592
|
+
Copy the full workflow from
|
|
593
|
+
[`docs/examples/github-actions-scan.yml`](docs/examples/github-actions-scan.yml)
|
|
594
|
+
into your app's repo. Pin the Penthera version so a scheduled run never picks up
|
|
595
|
+
code you have not reviewed.
|
|
596
|
+
|
|
597
|
+
Penthera's own CI runs the full test suite on Node 22 and 24, self-scans a mock
|
|
598
|
+
vulnerable API on every push, and runs CodeQL and OpenSSF Scorecard.
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
## Ethical use & authorization
|
|
603
|
+
|
|
604
|
+
Penthera sends HTTP requests to the targets you give it. Some modes (`--deep`,
|
|
605
|
+
`--fuzz`, `--all`) send attack payloads designed to find vulnerabilities. Use it
|
|
606
|
+
responsibly.
|
|
607
|
+
|
|
608
|
+
**You may use Penthera when:**
|
|
609
|
+
|
|
610
|
+
- You **own** the target (your app, your server, your project).
|
|
611
|
+
- You have **written authorization** from the system owner (email, ticket, signed scope).
|
|
612
|
+
- You scan **localhost** or private lab environments you control.
|
|
613
|
+
- You use it for **defensive security**: research, coursework, CI hardening, pre-release audits.
|
|
614
|
+
|
|
615
|
+
**You must not use Penthera to:**
|
|
616
|
+
|
|
617
|
+
- Scan systems you do not own or lack explicit permission to test.
|
|
618
|
+
- Probe government, healthcare, financial, or third-party production systems without authorization.
|
|
619
|
+
- Exfiltrate data, disrupt services, or bypass access controls.
|
|
620
|
+
- Use findings to attack, extort, or harm anyone.
|
|
621
|
+
|
|
622
|
+
> Before scanning any URL that is not localhost, confirm you have permission.
|
|
623
|
+
> **When in doubt, do not scan.**
|
|
624
|
+
|
|
625
|
+
Unauthorized security testing may violate computer-misuse laws (for example the US
|
|
626
|
+
CFAA, the UK Computer Misuse Act, and EU national equivalents) and can result in
|
|
627
|
+
criminal prosecution, civil liability, IP blocking, account termination, and
|
|
628
|
+
academic or professional penalties.
|
|
629
|
+
|
|
630
|
+
---
|
|
631
|
+
|
|
632
|
+
## Install
|
|
633
|
+
|
|
634
|
+
The [one-line installer](#run-it) is the fastest path. To set it up manually:
|
|
635
|
+
|
|
636
|
+
```bash
|
|
637
|
+
git clone https://github.com/danoszz/penthera.git
|
|
638
|
+
cd penthera
|
|
639
|
+
npm install
|
|
640
|
+
npm link # exposes `penthera` and `penthera-scan` globally
|
|
641
|
+
penthera --version
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
Requirements: Node.js 22+ and npm. Optional: nuclei-templates for `--nuclei`, and
|
|
645
|
+
Docker. To run it in a container:
|
|
646
|
+
|
|
647
|
+
```bash
|
|
648
|
+
docker build -t penthera .
|
|
649
|
+
docker run --rm penthera https://your-app.example
|
|
650
|
+
```
|
|
526
651
|
|
|
527
652
|
---
|
|
528
653
|
|
|
@@ -547,9 +672,8 @@ npm run pentest:mock # offline tests against a local mock vuln API
|
|
|
547
672
|
npm run mock-server # start the mock API on port 8765
|
|
548
673
|
```
|
|
549
674
|
|
|
550
|
-
See the [roadmap](ROADMAP.md) for what is next
|
|
551
|
-
|
|
552
|
-
See the [roadmap](ROADMAP.md) for what is next and what is deliberately not
|
|
675
|
+
See the [roadmap](ROADMAP.md) for what is next, including auditing the skills,
|
|
676
|
+
MCP servers, and plugins in your AI toolchain, and what is deliberately not
|
|
553
677
|
planned.
|
|
554
678
|
|
|
555
679
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for the project layout, how to add a probe
|
|
@@ -557,13 +681,34 @@ or template, the test matrix, and the release and publishing checklist.
|
|
|
557
681
|
|
|
558
682
|
---
|
|
559
683
|
|
|
684
|
+
## Methodology and accuracy
|
|
685
|
+
|
|
686
|
+
How Penthera decides what is a finding, how sure it is, and what it cannot
|
|
687
|
+
see is written up in [docs/METHODOLOGY.md](docs/METHODOLOGY.md), with every
|
|
688
|
+
design choice tied to published research or a standard
|
|
689
|
+
([references](docs/references.md)). Reports carry the same citations: each
|
|
690
|
+
finding gets a "Why this matters / Sources" line, and SARIF rules link to their
|
|
691
|
+
source.
|
|
692
|
+
|
|
693
|
+
Accuracy is measured, not claimed. `npm run bench` scans local labelled
|
|
694
|
+
targets offline and scores precision and recall; the current run is 19 true
|
|
695
|
+
positives, 3 false positives and 2 false negatives (precision 0.86, recall
|
|
696
|
+
0.90). The [results](bench/RESULTS.md) list every miss and false alarm, and
|
|
697
|
+
the [benchmark README](bench/README.md) explains the method and its limits.
|
|
698
|
+
|
|
699
|
+
To cite Penthera, use the "Cite this repository" button on GitHub
|
|
700
|
+
([CITATION.cff](CITATION.cff)).
|
|
701
|
+
|
|
702
|
+
---
|
|
703
|
+
|
|
560
704
|
## Status
|
|
561
705
|
|
|
562
|
-
**
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
for the full history.
|
|
706
|
+
**Production-ready and moving fast.** App scanning (URL, repo, macOS machine),
|
|
707
|
+
dependency capability analysis and an install firewall, the AI-tooling audit, the
|
|
708
|
+
local fix loop with a learning store, audience reports and evidence bundles, the
|
|
709
|
+
PR-comment GitHub Action, and NIS2 readiness tooling are all shipped. See the
|
|
710
|
+
[CHANGELOG](CHANGELOG.md) for the full history and the [roadmap](ROADMAP.md) for
|
|
711
|
+
what is next.
|
|
567
712
|
|
|
568
713
|
Penthera is actively maintained. Issues and PRs welcome.
|
|
569
714
|
|
|
@@ -576,8 +721,18 @@ you can help keep it maintained:
|
|
|
576
721
|
|
|
577
722
|
[](https://github.com/sponsors/danoszz)
|
|
578
723
|
|
|
579
|
-
|
|
580
|
-
|
|
724
|
+
| Tier | Monthly | You get |
|
|
725
|
+
|------|---------|---------|
|
|
726
|
+
| Individual | $5 | Thanks, and your name on the GitHub sponsors list |
|
|
727
|
+
| Supporter | $25 | A mention in the next release notes |
|
|
728
|
+
| Startup | $100 | Your name and link in this README |
|
|
729
|
+
| Company | $500 | Your logo in this README, and a quarterly roadmap call |
|
|
730
|
+
|
|
731
|
+
Sponsorship pays for maintainer time: keeping detection rules current, security
|
|
732
|
+
fixes, and the [roadmap](ROADMAP.md). It does not buy influence over findings,
|
|
733
|
+
a support SLA, or early access to vulnerability reports, and a logo here is not
|
|
734
|
+
a security endorsement of that company. Details in
|
|
735
|
+
[docs/funding/sponsor-tiers.md](docs/funding/sponsor-tiers.md).
|
|
581
736
|
|
|
582
737
|
---
|
|
583
738
|
|
|
@@ -585,15 +740,63 @@ current with new attack patterns. Thank you.
|
|
|
585
740
|
|
|
586
741
|
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.
|
|
587
742
|
|
|
588
|
-
- **Scan traffic goes
|
|
743
|
+
- **Scan traffic goes to the target you specify.** Auth tokens passed via `--auth-bearer`, `--auth-cookie`, or `PENTHERA_*` env vars are sent only to that target.
|
|
744
|
+
- **Every request identifies itself** as `penthera/<version> (+https://github.com/danoszz/penthera)`, so a target's operator can tell where the traffic comes from. Override it with `--user-agent`.
|
|
589
745
|
- **Reports stay local.** Output is written to `reports/` (gitignored) on your machine.
|
|
590
|
-
- **
|
|
591
|
-
|
|
746
|
+
- **Every scan lists the third-party hosts it contacted** besides the target, in the terminal summary and in the report's "Network egress" section.
|
|
747
|
+
|
|
748
|
+
Without `--offline`, a scan may contact these third parties:
|
|
749
|
+
|
|
750
|
+
| Host | When | What it learns |
|
|
751
|
+
|---|---|---|
|
|
752
|
+
| `raw.githubusercontent.com`, `cdn.jsdelivr.net` | Retire.js check (standard and deep profiles) | That someone downloaded the public database. Nothing about your target. |
|
|
753
|
+
| `crt.sh`, `web.archive.org`, `otx.alienvault.com` | `--recon` only | The target domain. |
|
|
754
|
+
| 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. |
|
|
755
|
+
|
|
756
|
+
### Fully local: `--offline`
|
|
757
|
+
|
|
758
|
+
```bash
|
|
759
|
+
penthera http://localhost:3000 --offline
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
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:
|
|
763
|
+
|
|
764
|
+
- **Recon is skipped.** No queries go to crt.sh, the Wayback Machine or OTX.
|
|
765
|
+
- **The Retire.js database comes from the snapshot vendored in the package** (`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.
|
|
766
|
+
- **Third-party scripts are not fetched.** A refused request is listed in the report as an inconclusive probe, not passed over silently.
|
|
767
|
+
- **`--suppliers` is refused**, because it rates third-party domains.
|
|
768
|
+
- **DNS:** reaching a remote target needs DNS. For non-local targets, the email-authentication check also looks up the target domain's SPF/DMARC/MX records through your system resolver. A `localhost` or IP target needs no DNS at all.
|
|
769
|
+
|
|
770
|
+
Penthera never fetches rules or code at runtime: templates, wordlists and the vulnerability database ship in the package.
|
|
771
|
+
|
|
772
|
+
### Inconclusive probes
|
|
773
|
+
|
|
774
|
+
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.
|
|
592
775
|
|
|
593
776
|
You are responsible for ensuring you are authorized to scan any target. See [Ethical use](#ethical-use--authorization).
|
|
594
777
|
|
|
595
778
|
---
|
|
596
779
|
|
|
780
|
+
## Disclaimer
|
|
781
|
+
|
|
782
|
+
Penthera is provided for legitimate security research and defensive testing of
|
|
783
|
+
systems you own or are authorized to test, and for that purpose only.
|
|
784
|
+
|
|
785
|
+
- It is a research and self-assessment tool. Scan your own apps to find and fix
|
|
786
|
+
weaknesses before attackers do.
|
|
787
|
+
- The same capabilities that harden a system can cause harm if pointed at someone
|
|
788
|
+
else's. Use it carefully and lawfully.
|
|
789
|
+
- The author does not condone unauthorized or malicious use, and accepts no
|
|
790
|
+
liability for any damage, loss, or legal consequence arising from use or misuse
|
|
791
|
+
of this software.
|
|
792
|
+
- The software is provided "as is", without warranty of any kind. See [LICENSE](LICENSE) (MIT).
|
|
793
|
+
- You are solely responsible for ensuring every scan you run is authorized and
|
|
794
|
+
legal in your jurisdiction.
|
|
795
|
+
|
|
796
|
+
By using Penthera you accept these terms.
|
|
797
|
+
|
|
798
|
+
---
|
|
799
|
+
|
|
597
800
|
## License & disclosure
|
|
598
801
|
|
|
599
802
|
MIT. See [LICENSE](LICENSE). Report vulnerabilities in Penthera itself via
|