penthera 1.6.1 → 1.7.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +158 -301
  3. package/bin/scan.js +2 -2
  4. package/docs/METHODOLOGY.md +236 -182
  5. package/docs/commands/README.md +2 -1
  6. package/docs/commands/init.md +114 -0
  7. package/docs/commands/scan.md +1 -1
  8. package/docs/compare/github.md +1 -1
  9. package/docs/dashboard.md +95 -152
  10. package/docs/examples/github-actions-scan.yml +1 -1
  11. package/docs/internal-audit.md +1 -1
  12. package/docs/plan.md +3 -2
  13. package/docs/references.bib +43 -33
  14. package/docs/references.md +92 -51
  15. package/lib/whitebox/frameworks.js +36 -0
  16. package/package.json +1 -1
  17. package/skills/penthera/SKILL.md +19 -5
  18. package/src/cli/deps.js +1 -1
  19. package/src/cli/detect.js +125 -0
  20. package/src/cli/onboarding.js +428 -6
  21. package/src/cli/prompt.js +42 -0
  22. package/src/cli.js +18 -5
  23. package/src/ui/api/data.js +30 -0
  24. package/src/ui/api/demo.js +13 -0
  25. package/src/ui/api/routes.js +1 -0
  26. package/src/ui/static/app.css +286 -560
  27. package/src/ui/static/index.html +8 -39
  28. package/src/ui/static/js/app.js +105 -107
  29. package/src/ui/static/js/center.js +388 -0
  30. package/src/ui/static/js/copy.js +36 -62
  31. package/src/ui/static/js/dom.js +0 -38
  32. package/src/ui/static/js/left.js +83 -0
  33. package/src/ui/static/js/right.js +270 -0
  34. package/src/ui/static/js/state.js +35 -0
  35. package/src/ui/static/js/views/ai.js +0 -68
  36. package/src/ui/static/js/views/deps.js +0 -96
  37. package/src/ui/static/js/views/evidence.js +0 -115
  38. package/src/ui/static/js/views/findings.js +0 -165
  39. package/src/ui/static/js/views/history.js +0 -92
  40. package/src/ui/static/js/views/overview.js +0 -184
  41. package/src/ui/static/js/views/run.js +0 -349
  42. package/src/ui/static/js/views/settings.js +0 -67
@@ -1,13 +1,50 @@
1
1
  # Methodology
2
2
 
3
- This document describes what Penthera tests, how it decides that something is a
4
- finding, how sure it is, and where its limits are. Each design choice points to
5
- the research or standard it rests on. Citation keys such as `[bau2010state]`
6
- refer to [references.md](references.md) and [references.bib](references.bib).
7
-
8
- Measured accuracy on the bundled benchmark is in
9
- [bench/RESULTS.md](../bench/RESULTS.md); the method behind those numbers is in
10
- [bench/README.md](../bench/README.md).
3
+ ## Abstract
4
+
5
+ Penthera is an open-source, offline security scanner for web applications,
6
+ their dependencies, and the AI tooling used to build them. This document
7
+ specifies its method. It states the threat model, separates what black-box
8
+ (HTTP) and white-box (repository) analysis can and cannot observe, and defines
9
+ a four-level confidence model that distinguishes deterministic evidence from
10
+ heuristic signals. It describes the false-positive controls built into each
11
+ probe (randomized canaries, context-aware payload selection, baseline
12
+ comparison, and repeated timing measurement) and the non-destructive defaults
13
+ that follow from fail-safe design. Detection rules are distributed only in
14
+ reviewed, versioned releases, never through a live feed, which removes an
15
+ update channel from the attack surface. Each design choice is tied to prior
16
+ research or a published standard. On a bundled benchmark of labelled local
17
+ targets, Penthera reaches a precision of 0.86 and a recall of 0.90. Because the
18
+ same authors wrote the scanner and the targets, these figures measure
19
+ regressions, not accuracy on arbitrary applications.
20
+
21
+ ## How to cite
22
+
23
+ If you use Penthera or this methodology in research or a report, cite the
24
+ software. The metadata are in [CITATION.cff](../CITATION.cff), which GitHub
25
+ renders as "Cite this repository".
26
+
27
+ ```text
28
+ van der Zwaag, D. (2026). Penthera: An offline security scanner for web apps and AI-built code (Version 1.7.0) [Computer software]. https://github.com/danoszz/penthera
29
+ ```
30
+
31
+ ```bibtex
32
+ @software{vanderzwaag2026penthera,
33
+ author = {van der Zwaag, Daan},
34
+ title = {Penthera: An Offline Security Scanner for Web Apps and {AI}-Built Code},
35
+ year = {2026},
36
+ version = {1.7.0},
37
+ license = {MIT},
38
+ url = {https://github.com/danoszz/penthera}
39
+ }
40
+ ```
41
+
42
+ Citations in this document follow APA 7th edition. Each one resolves to an
43
+ entry in [references.md](references.md), generated from
44
+ [references.bib](references.bib); a test fails if a citation has no entry or an
45
+ entry is never cited. Measured accuracy is in
46
+ [bench/RESULTS.md](../bench/RESULTS.md), and the method behind those numbers is
47
+ in [bench/README.md](../bench/README.md).
11
48
 
12
49
  ## Contents
13
50
 
@@ -23,52 +60,56 @@ Measured accuracy on the bundled benchmark is in
23
60
 
24
61
  ## Threat model
25
62
 
26
- Penthera is built for small teams shipping web apps and APIs, often with AI
27
- coding tools, who need a first line of evidence before a human review or a
28
- paid penetration test. The threat model follows the structure in Shostack
29
- [shostack2014threat]: what are we building, what can go wrong, what do we do
30
- about it, and did we do a good job.
63
+ Penthera is built for small teams that ship web apps and APIs, often with AI
64
+ coding tools, and need a first line of evidence before a human review or a paid
65
+ penetration test. The threat model follows the four questions of Shostack
66
+ (2014): what are we building, what can go wrong, what are we going to do about
67
+ it, and did we do a good job.
31
68
 
32
- **Assets.** User data behind the API, credentials and API keys (including AI
33
- provider keys), the session and identity layer, and the integrity of the code
34
- and dependencies that get deployed.
69
+ **Assets.** User data behind the API; credentials and API keys, including AI
70
+ provider keys; the session and identity layer; and the integrity of the code and
71
+ dependencies that get deployed.
35
72
 
36
73
  **Adversaries in scope.**
37
74
 
38
75
  1. A remote, unauthenticated attacker on the internet who can send arbitrary
39
- HTTP requests to the deployed app. This is what the black-box scan models.
40
- 2. An authenticated user trying to reach another user's data (broken object
41
- level authorization, the top item in the OWASP API Security Top 10
42
- [owasp2023api]). Penthera tests this when given credentials.
76
+ HTTP requests to the deployed app. The black-box scan models this attacker.
77
+ 2. An authenticated user who tries to reach another user's data. Broken object
78
+ level authorization is the first item in the OWASP API Security Top 10
79
+ (OWASP Foundation, 2023). Penthera tests for it when given credentials.
43
80
  3. Anyone who obtains a copy of the source: a leaked repository, a public fork,
44
- a compromised CI log. Meli et al. found secrets leaked in over 100,000
45
- public GitHub repositories, with thousands of new, unique secrets leaked
46
- every day [meli2019bad]. This is what the
47
- white-box secret scan models.
48
- 4. A supply-chain attacker who publishes or compromises a dependency
49
- [ladisa2023sok, ohm2020backstabber, zimmermann2019small], including
50
- packages that code-generating models invent and attackers then register
51
- [spracklen2025package].
52
-
53
- **Out of scope.** Physical access, insider threats with production access,
54
- denial of service, social engineering, and anything that needs exploitation
55
- beyond a single benign probe. Penthera does not try to replace a human tester;
56
- it tries to find the issues a scanner can find reliably and say clearly which
57
- ones it cannot judge.
81
+ or a compromised CI log. Meli et al. (2019) found secrets leaked in over
82
+ 100,000 public GitHub repositories, with thousands of new, unique secrets
83
+ leaked every day. The white-box secret scan models this adversary.
84
+ 4. A supply-chain attacker who publishes or compromises a dependency (Ladisa et
85
+ al., 2023; Ohm et al., 2020; Zimmermann et al., 2019), including packages
86
+ that code-generating models invent and attackers then register (Spracklen
87
+ et al., 2025).
88
+
89
+ **Out of scope.** Physical access, insiders with production access, denial of
90
+ service, social engineering, and anything that needs exploitation beyond a
91
+ single benign probe. Penthera does not try to replace a human tester. It tries
92
+ to find the issues a scanner can find reliably, and to say clearly which ones
93
+ it cannot judge.
58
94
 
59
95
  **Penthera itself is in the threat model.** A security tool runs with the
60
96
  user's credentials and network position, so a compromised scanner is a
61
- compromised machine. Thompson's point that you cannot trust code you did not
62
- build yourself [thompson1984reflections] applies to scanners and their rule
63
- feeds. This is why Penthera fetches no rules at run time
97
+ compromised machine. Thompson (1984) showed that you cannot fully trust code you
98
+ did not build yourself; the argument applies to scanners and their rule feeds.
99
+ This is why Penthera fetches no rules at run time
64
100
  ([below](#how-new-attack-techniques-are-adopted)).
65
101
 
66
- STRIDE, the threat categories that Shostack's book builds on, originates at
67
- Microsoft [kohnfelder1999threats]. Penthera's probes map onto it roughly as:
68
- spoofing (auth, JWT, OAuth, email SPF/DMARC), tampering (injection, CORS),
69
- repudiation (not tested), information disclosure (exposed files, secrets,
70
- verbose errors), denial of service (not tested, only rate limiting is
71
- checked), and elevation of privilege (IDOR/BOLA, client-side-only auth).
102
+ STRIDE, the threat taxonomy that Shostack's book builds on, originates at
103
+ Microsoft (Kohnfelder & Garg, 1999). Penthera's probes map onto it as follows:
104
+
105
+ | STRIDE category | Penthera coverage |
106
+ |---|---|
107
+ | Spoofing | Authentication, JWT, OAuth, email SPF and DMARC |
108
+ | Tampering | Injection, CORS |
109
+ | Repudiation | Not tested |
110
+ | Information disclosure | Exposed files, secrets, verbose errors |
111
+ | Denial of service | Not tested; only rate limiting is checked |
112
+ | Elevation of privilege | IDOR/BOLA, client-side-only authorization |
72
113
 
73
114
  ## Black-box and white-box: what each can find
74
115
 
@@ -77,40 +118,39 @@ Penthera runs two kinds of analysis and reports them together.
77
118
  ### Black-box (URL scan)
78
119
 
79
120
  The scanner sees only HTTP responses. Its tests are those of the OWASP Web
80
- Security Testing Guide [owaspwstg42]; each probe's WSTG IDs are listed in
81
- [owasp-wstg-coverage.md](owasp-wstg-coverage.md).
121
+ Security Testing Guide (OWASP Foundation, n.d.-b); each probe's WSTG IDs are
122
+ listed in [owasp-wstg-coverage.md](owasp-wstg-coverage.md).
82
123
 
83
- What black-box testing finds well: properties that are visible in every
124
+ Black-box testing finds three kinds of issue well: properties visible in every
84
125
  response (missing security headers, TLS configuration, cookie flags, CORS
85
126
  policy), files and interfaces that should not be public, and injection flaws
86
- whose effect shows up in the response or its timing. Protocol checks follow
87
- the relevant specifications: HSTS [hodges2012rfc6797], JWT
88
- [jones2015rfc7519, sheffer2020rfc8725], and OAuth redirect and PKCE handling
89
- [lodderstedt2025rfc9700, sakimura2015rfc7636, fett2016comprehensive].
90
-
91
- What it misses, and why. Two classic evaluations of black-box scanners point
92
- the same way. Bau et al. tested eight commercial scanners against a custom
93
- vulnerable application and older versions of real ones. As a group the tools
94
- did reasonably well, but second-order flaws, stored XSS and stored SQL
95
- injection, were missed by many of them [bau2010state]. Doupé et al. tested
96
- eleven commercial and open-source scanners against WackoPicko, a realistic
97
- purpose-built app with sixteen planted flaws. Eight of the sixteen were missed
98
- by every scanner, including stored SQL injection, multi-step stored XSS,
99
- forceful browsing and a business logic flaw. They concluded that crawling
100
- matters as much as detection: a scanner cannot test a page it never reaches,
101
- and losing track of state (logins, multi-step forms) is a main reason it
102
- doesn't [doupe2010johnny].
127
+ whose effect shows in the response or its timing. Protocol checks follow the
128
+ relevant specifications: HSTS (Hodges et al., 2012), JWT (Jones et al., 2015;
129
+ Sheffer et al., 2020), and OAuth redirect and PKCE handling (Fett et al., 2016;
130
+ Lodderstedt et al., 2025; Sakimura et al., 2015).
131
+
132
+ Two classic evaluations of black-box scanners show what this approach misses.
133
+ Bau et al. (2010) tested eight commercial scanners against a custom vulnerable
134
+ application and older versions of real ones. As a group the tools did
135
+ reasonably well, but many of them missed second-order flaws such as stored XSS
136
+ and stored SQL injection. Doupé et al. (2010) tested eleven commercial and
137
+ open-source scanners against WackoPicko, a realistic purpose-built app with
138
+ sixteen planted flaws. Every scanner missed eight of the sixteen, among them
139
+ stored SQL injection, multi-step stored XSS, forceful browsing, and a business
140
+ logic flaw. They concluded that crawling matters as much as detection: a
141
+ scanner cannot test a page it never reaches, and losing track of state (logins,
142
+ multi-step forms) is a main reason it does not reach it.
103
143
 
104
144
  Penthera's design responds to each point:
105
145
 
106
146
  - **Crawl coverage.** Endpoint discovery uses a wordlist plus the app's own
107
147
  OpenAPI document when one is exposed, and records exactly which probes ran.
108
- The WSTG coverage table in every report lists tests as run or not run, so a
109
- missing check is never presented as a pass.
148
+ The WSTG coverage table in every report lists each test as run or not run, so
149
+ a missing check is never presented as a pass.
110
150
  - **State and logic.** Penthera does not claim to find business logic flaws,
111
- which no scanner in the Doupé et al. study found either.
112
- IDOR/BOLA results are labelled `needs-human-review` because a scanner cannot
113
- know whether user A is allowed to read object B.
151
+ which no scanner in the study by Doupé et al. (2010) found either. IDOR/BOLA
152
+ results are labelled `needs-human-review` because a scanner cannot know
153
+ whether user A is allowed to read object B.
114
154
  - **Stored and second-order flaws.** Not tested. They need a write followed by
115
155
  a read elsewhere, which conflicts with the non-destructive default.
116
156
 
@@ -119,33 +159,32 @@ Penthera's design responds to each point:
119
159
  The scanner reads source files. It finds hardcoded secrets, route handlers and
120
160
  their authentication boundaries, and risky code patterns.
121
161
 
122
- Secret detection uses provider-specific prefixes (for example `AKIA` for AWS,
123
- `sk-ant-` for Anthropic) plus a small number of assignment patterns such as
124
- `api_key = "..."` with a placeholder filter. Meli et al. took the same
125
- conservative route, restricting detection to private keys and API keys with
126
- distinctive formats [meli2019bad]. The cost is recall: a secret with no
127
- recognisable format is invisible to this approach. SecretBench, a labelled
128
- dataset of real secrets across many formats, is the natural yardstick for that
129
- gap [basak2023secretbench]. The benchmark here includes an unprefixed signing
130
- key that Penthera misses for this reason.
162
+ Secret detection uses provider-specific prefixes (for example `AKIA` for AWS
163
+ and `sk-ant-` for Anthropic) plus a small number of assignment patterns such as
164
+ `api_key = "..."` with a placeholder filter. Meli et al. (2019) took the same
165
+ conservative route and restricted detection to private keys and API keys with
166
+ distinctive formats. The cost is recall: a secret with no recognisable format
167
+ is invisible to this approach. SecretBench, a labelled dataset of real secrets
168
+ across many formats, is the natural yardstick for that gap (Basak et al.,
169
+ 2023). The bundled benchmark includes an unprefixed signing key that Penthera
170
+ misses for this reason.
131
171
 
132
- What white-box scanning cannot see: runtime configuration (headers added by a
133
- CDN, a WAF in front of the app), secrets injected at deploy time, and anything
134
- in dependencies that is only known from a vulnerability database.
172
+ White-box scanning cannot see runtime configuration (headers added by a CDN, a
173
+ WAF in front of the app), secrets injected at deploy time, or anything in
174
+ dependencies that is only known from a vulnerability database.
135
175
 
136
176
  ### Combining them
137
177
 
138
178
  Running both against the same app catches cases neither sees alone: a route
139
179
  the repository marks as public that the black-box scan confirms is reachable,
140
- or a header the code sets that the edge strips. The report keeps the source of
180
+ or a header the code sets that the edge strips. The report keeps the origin of
141
181
  each finding (`source`, `method`) so a reader can tell which side produced it.
142
182
 
143
183
  ## Confidence model
144
184
 
145
185
  Severity says how bad a finding would be if real. Confidence says how likely it
146
- is to be real. Penthera reports both, and never lets a heuristic look like a
147
- fact. The labels are defined in
148
- [lib/provenance.js](../lib/provenance.js):
186
+ is to be real. Penthera reports both and never lets a heuristic look like a
187
+ fact. The labels are defined in [lib/provenance.js](../lib/provenance.js):
149
188
 
150
189
  | Label | Meaning | Typical sources |
151
190
  |---|---|---|
@@ -154,120 +193,121 @@ fact. The labels are defined in
154
193
  | `potential` | A heuristic or one-shot signal that needs corroboration. | Fuzzer, adaptive probes |
155
194
  | `needs-human-review` | Exploitability cannot be judged from outside. | IDOR/BOLA, client-side-only auth |
156
195
 
157
- Every finding also carries `source`, `method` and `collected_at`, and these
158
- travel into SARIF so the label survives into GitHub code scanning.
196
+ Every finding also carries `source`, `method`, and `collected_at`. These travel
197
+ into SARIF, so the label survives into GitHub code scanning.
159
198
 
160
- The benchmark reports precision per confidence label, which is the check that
161
- the labels mean what they say. On the current run all `likely` and
162
- `needs-human-review` findings were true positives, the one `potential` finding
163
- was a false positive, and the two `confirmed` false positives are cases where
164
- the evidence is real but the judgement is wrong (a health endpoint that is
165
- public by design, AWS's published example key). See
199
+ The benchmark reports precision per confidence label, which tests whether the
200
+ labels mean what they say. On the current run, all `likely` and
201
+ `needs-human-review` findings were true positives and the one `potential`
202
+ finding was a false positive. The two `confirmed` false positives are cases
203
+ where the evidence is real but the judgement is wrong: a health endpoint that
204
+ is public by design, and AWS's published example key. See
166
205
  [bench/RESULTS.md](../bench/RESULTS.md).
167
206
 
168
207
  ## False-positive controls
169
208
 
170
- Black-box scanners lose trust through false positives faster than through
171
- misses. Specific controls in the probes:
209
+ A black-box scanner loses trust through false positives faster than through
210
+ misses. The probes apply these controls:
172
211
 
173
212
  - **Randomized canaries.** The SSTI probe multiplies two random four-digit
174
- numbers and looks for the seven- or eight-digit product, and only when the
175
- raw payload and the literal expression are absent from the response
213
+ numbers and looks for the seven- or eight-digit product, and only when
214
+ neither the raw payload nor the literal expression appears in the response
176
215
  ([lib/injections.js](../lib/injections.js), `buildSstiProbes`). The common
177
- fixed `7*7 = 49` canary fires on any page that happens to contain "49". XSS
178
- probes use a per-probe random reflection marker (`makeCanary`).
216
+ fixed canary `7*7 = 49` fires on any page that happens to contain "49". XSS
217
+ probes use a random reflection marker per probe (`makeCanary`).
179
218
  - **Context before payload.** The XSS probe first checks where its marker is
180
- reflected (HTML body, attribute, script) and only sends payloads that would
181
- execute in that context, then checks they came back unencoded. This is the
182
- approach of context-aware tools such as Dalfox.
183
- - **Baseline comparison.** Error-based SQL injection is only reported when the
219
+ reflected (HTML body, attribute, or script), sends only payloads that would
220
+ execute in that context, and then checks that they came back unencoded.
221
+ Context-aware tools such as Dalfox take the same approach.
222
+ - **Baseline comparison.** Error-based SQL injection is reported only when the
184
223
  database error appears in the injected response and not in the baseline.
185
224
  - **Timing re-sampling.** A single slow response proves nothing: garbage
186
- collection, cold starts and network jitter all look like an injected sleep.
187
- Time-based SQL and command injection candidates are re-sent and only
188
- reported when the median delay holds (`confirmTimingDelay`). Crosby et al.
225
+ collection, cold starts, and network jitter all look like an injected sleep.
226
+ Time-based SQL and command injection candidates are re-sent and reported only
227
+ when the median delay holds (`confirmTimingDelay`). Crosby et al. (2009)
189
228
  showed that network jitter dominates single remote timing measurements and
190
- that filtering over many samples is what makes them usable
191
- [crosby2009opportunities], building on Kocher's original timing attacks
192
- [kocher1996timing]. Penthera's delays are seconds, not microseconds, so a
193
- median of three samples is enough.
194
- - **Host-checked redirects.** An open redirect is reported only if the
195
- `Location` header actually resolves to the attacker host, not when the
196
- payload merely appears in a same-site redirect's query string.
229
+ that filtering over many samples is what makes them usable, building on the
230
+ original timing attacks of Kocher (1996). Penthera's injected delays are
231
+ seconds, not microseconds, so a median of three samples is enough.
232
+ - **Host-checked redirects.** An open redirect is reported only when the
233
+ `Location` header resolves to the attacker host, not when the payload merely
234
+ appears in the query string of a same-site redirect.
197
235
  - **Context-aware suppression.** On localhost and private hosts, findings that
198
- do not apply (no HTTPS, missing `Secure` on cookies) are suppressed.
236
+ do not apply there (no HTTPS, missing `Secure` on cookies) are suppressed.
199
237
 
200
- The benchmark's decoy target exercises each of these with an endpoint built to
201
- fool a naive scanner. Writing it found one real problem in the decoy itself: a
238
+ The benchmark's decoy target exercises each control with an endpoint built to
239
+ fool a naive scanner. Writing it exposed one real flaw in the decoy itself: a
202
240
  "safe" redirect that accepted `/\evil.com`, which browsers treat as
203
241
  `//evil.com`. Penthera reported it correctly.
204
242
 
205
243
  ## Non-destructive by default
206
244
 
207
245
  The `quick` and `standard` profiles send only requests a normal browser or API
208
- client would send: GETs, `OPTIONS`, and invalid login attempts. They do not
246
+ client would send: `GET`, `OPTIONS`, and invalid login attempts. They do not
209
247
  send attack payloads, create or modify data, or exploit anything they find.
210
248
 
211
249
  Payload-based testing (`--deep`, `--fuzz`, `--adaptive`, or `--profile deep`)
212
- is opt-in and gated behind a confirmation prompt. Even then each probe sends a
213
- benign marker (a random string, arithmetic, a short sleep, `id`) rather than a
214
- working exploit, and stops at the first confirmation per endpoint. The
215
- adaptive engine may send unexpected HTTP methods, including `DELETE`, to
216
- routes with placeholder IDs; it is therefore never part of a default run.
217
-
218
- This follows Saltzer and Schroeder's fail-safe defaults and least privilege
219
- [saltzer1975protection]: the default does the least that is still useful, and
220
- anything riskier needs an explicit decision. NIST SP 800-115 makes the same
221
- distinction between non-intrusive assessment and penetration testing, and
222
- recommends written rules of engagement before the latter
223
- [scarfone2008sp800115].
250
+ is opt-in and gated behind a confirmation prompt. Even then, each probe sends a
251
+ benign marker (a random string, an arithmetic expression, a short sleep, `id`)
252
+ rather than a working exploit, and stops at the first confirmation per
253
+ endpoint. The adaptive engine may send unexpected HTTP methods, including
254
+ `DELETE`, to routes with placeholder IDs, so it is never part of a default run.
255
+
256
+ This follows the principles of fail-safe defaults and least privilege set out by
257
+ Saltzer and Schroeder (1975): the default does the least that is still useful,
258
+ and anything riskier needs an explicit decision. NIST SP 800-115 draws the same
259
+ line between non-intrusive assessment and penetration testing, and recommends
260
+ written rules of engagement before the latter (Scarfone et al., 2008).
224
261
 
225
262
  ## Offline and no telemetry
226
263
 
227
- Penthera does not phone home. It sends no usage data, analytics or crash
264
+ Penthera does not phone home. It sends no usage data, analytics, or crash
228
265
  reports, and it has no accounts. Reports are written to local files.
229
266
 
230
267
  Network traffic goes to the target you name, with two documented exceptions:
231
268
 
232
- 1. `--recon` (and the `deep` profile) queries public OSINT sources (crt.sh,
233
- the Wayback Machine, AlienVault OTX) with the target domain. It is skipped
234
- for localhost.
269
+ 1. `--recon` (and the `deep` profile) queries public OSINT sources (crt.sh, the
270
+ Wayback Machine, AlienVault OTX) with the target domain. It is skipped for
271
+ localhost.
235
272
  2. The Retire.js check downloads the public Retire.js vulnerability database
236
- from GitHub to compare JavaScript library versions locally. This is data,
237
- not code: it is parsed as JSON and never executed. It is the one place a
238
- detection input arrives at run time, and the roadmap's `--offline` egress
239
- guard replaces it with a vendored copy shipped in releases.
240
-
241
- The benchmark enforces offline operation mechanically: it wraps `fetch` so any
242
- request to a non-loopback host is refused and counted, and fails if the count
243
- is not zero.
244
-
245
- These choices follow economy of mechanism and complete mediation
246
- [saltzer1975protection]: fewer network paths means fewer things to audit, and
247
- a tool that talks only to the target is easy to reason about in a regulated
248
- environment.
273
+ from GitHub and compares JavaScript library versions locally. Outdated
274
+ client-side libraries are common on the web and often carry known
275
+ vulnerabilities (Lauinger et al., 2017). The database is data, not code: it
276
+ is parsed as JSON and never executed. It is the one place a detection input
277
+ arrives at run time. Under `--offline`, and whenever the download fails,
278
+ Penthera uses the snapshot vendored in the release instead.
279
+
280
+ The benchmark enforces offline operation mechanically. It wraps `fetch` so any
281
+ request to a non-loopback host is refused and counted, and it fails if the
282
+ count is not zero.
283
+
284
+ These choices follow the principles of economy of mechanism and complete
285
+ mediation (Saltzer & Schroeder, 1975): fewer network paths mean fewer things to
286
+ audit, and a tool that talks only to its target is easy to reason about in a
287
+ regulated environment.
249
288
 
250
289
  ## How new attack techniques are adopted
251
290
 
252
- Attack techniques change quickly. In the last few years: indirect prompt
253
- injection against LLM-integrated apps [greshake2023signed, perez2022ignore,
254
- liu2023prompt], package hallucination and slopsquatting
255
- [spracklen2025package], and attacks on agent tooling and MCP servers
256
- catalogued by OWASP [owasp2024llmtop10, owasp2025agentic, owasp2025mcptop10]
257
- and MITRE ATLAS [mitreatlas]. A scanner that does not keep up becomes a
258
- false sense of security.
291
+ Attack techniques change quickly. Recent examples include indirect prompt
292
+ injection against LLM-integrated applications (Greshake et al., 2023; Liu et
293
+ al., 2023; Perez & Ribeiro, 2022), package hallucination and slopsquatting
294
+ (Spracklen et al., 2025), and attacks on agent tooling and MCP servers,
295
+ catalogued by OWASP (OWASP Foundation, 2024, 2025a, 2025b) and in MITRE ATLAS
296
+ (The MITRE Corporation, n.d.-b). A scanner that does not keep up gives a false
297
+ sense of security.
259
298
 
260
- Penthera keeps up through reviewed releases, not through live updates:
299
+ Penthera keeps up through reviewed releases, not live updates:
261
300
 
262
- - **Rules ship as code in a release.** New probes, patterns and templates are
301
+ - **Rules ship as code in a release.** New probes, patterns, and templates are
263
302
  added by pull request, reviewed, tested against the benchmark, and published
264
303
  in a versioned release with a CHANGELOG entry. There is no rule server, no
265
304
  background update, and no command that fetches rules from the internet.
266
305
  - **Every new rule carries a source and a date.** A rule added after v1.2.0
267
306
  records where the technique comes from (a paper, an advisory, an OWASP or
268
- ATLAS entry, an incident write-up) and the date it was added. Categories are
269
- already linked to their sources in [lib/references.json](../lib/references.json);
270
- the built-in rules that predate this policy are being backfilled.
307
+ ATLAS entry, an incident write-up) and the date it was added. Finding
308
+ categories are already linked to their sources in
309
+ [lib/references.json](../lib/references.json); the built-in rules that
310
+ predate this policy are being backfilled.
271
311
  - **Every new rule comes with a benchmark case.** A detection rule is added
272
312
  together with a labelled true positive and, where a false positive is
273
313
  plausible, a decoy in [bench/](../bench/). The CI floor in the benchmark
@@ -276,25 +316,39 @@ Penthera keeps up through reviewed releases, not through live updates:
276
316
  load YAML templates from directories you choose. Penthera does not download
277
317
  them.
278
318
 
279
- Why not auto-update? A rule feed is a code path from someone else's server
280
- into a tool that runs with your network access and often your credentials.
281
- Supply-chain research shows that update channels and package registries are
282
- exactly where attackers insert themselves [ladisa2023sok, ohm2020backstabber,
283
- zimmermann2019small], and that securing an update channel needs signed
284
- metadata, key rotation and explicit trust delegation [samuel2010survivable,
285
- torresarias2019intoto]. Shipping rules inside the signed, versioned package
286
- reuses the trust you already place in the release, and gives a clear audit
287
- trail: the rules you ran are the rules in the version you installed.
319
+ Why not update automatically? A rule feed is a code path from someone else's
320
+ server into a tool that runs with your network access and often your
321
+ credentials. Supply-chain research shows that update channels and package
322
+ registries are exactly where attackers insert themselves (Ladisa et al., 2023;
323
+ Ohm et al., 2020; Zimmermann et al., 2019), and that securing an update channel
324
+ needs signed metadata, key rotation, and explicit trust delegation (Samuel et
325
+ al., 2010; Torres-Arias et al., 2019). Shipping rules inside the signed,
326
+ versioned package reuses the trust you already place in the release, and gives
327
+ a clear audit trail: the rules you ran are the rules in the version you
328
+ installed.
288
329
 
289
330
  ## Citations in reports
290
331
 
291
332
  Each finding category maps to one to three references in
292
- [lib/references.json](../lib/references.json). They appear:
333
+ [lib/references.json](../lib/references.json), chosen to explain why the
334
+ finding matters. Besides the sources discussed above, these include the
335
+ empirical work behind specific header and policy checks: Content Security
336
+ Policy (Weichselbaum et al., 2016), cookie handling and cross-site request
337
+ forgery (Barth et al., 2008), and CORS misconfiguration
338
+ (Chen et al., 2018). Email authentication findings cite the SPF and DMARC
339
+ specifications (Kitterman, 2014; Kucherawy & Zwicky, 2015). Injection,
340
+ exposure, and configuration findings cite the OWASP Top 10 (OWASP Foundation,
341
+ 2021, 2025c), code-pattern findings cite the Common Weakness Enumeration (The
342
+ MITRE Corporation, n.d.-a), and license findings use the identifiers of the
343
+ SPDX License List (SPDX Workgroup, The Linux Foundation, n.d.).
344
+
345
+ The references appear in two places:
293
346
 
294
347
  - in the Markdown report, as a "Why this matters / Sources" line under each
295
348
  finding and a "Sources" line under each action-plan item;
296
- - in SARIF [oasis2023sarif], as the rule's `helpUri` (first source) and
297
- `help` text (all sources), and as `properties.references` (the BibTeX keys).
349
+ - in SARIF (Fanning & Golding, 2023), as the rule's `helpUri` (first source)
350
+ and `help` text (all sources), and as `properties.references` (the BibTeX
351
+ keys).
298
352
 
299
353
  [references.md](references.md) and the `sources` block of `references.json`
300
354
  are generated from [references.bib](references.bib) by
@@ -303,19 +357,19 @@ are generated from [references.bib](references.bib) by
303
357
  ## Known limitations
304
358
 
305
359
  - No authenticated crawling beyond the bearer token or cookie you pass, so
306
- pages behind multi-step flows are not reached [doupe2010johnny].
307
- - No stored or second-order injection testing [bau2010state].
308
- - No DOM-based XSS analysis; Penthera does not run JavaScript
309
- [lekies2013flows, stock2014precise].
310
- - No business logic testing. IDOR/BOLA findings need a human to confirm.
311
- - Secret detection is pattern-based and skips Markdown and other
312
- documentation files, so unprefixed secrets and secrets in notes are missed.
360
+ pages behind multi-step flows are not reached (Doupé et al., 2010).
361
+ - No stored or second-order injection testing (Bau et al., 2010).
362
+ - No DOM-based XSS analysis, because Penthera does not run JavaScript (Lekies et
363
+ al., 2013; Stock et al., 2014).
364
+ - No business logic testing. IDOR/BOLA findings need a human to confirm them.
365
+ - Secret detection is pattern-based and skips Markdown and other documentation
366
+ files, so unprefixed secrets and secrets in notes are missed.
313
367
  - The bundled benchmark was written by the same people as the scanner. Its
314
368
  numbers measure regressions and the false-positive controls, not accuracy on
315
369
  arbitrary applications. Independent benchmarks such as the OWASP Benchmark
316
- [owaspbenchmark] and the approach of Antunes and Vieira
317
- [antunes2010benchmarking, antunes2015assessing] are the model for a fairer
318
- comparison, and scoring against labelled third-party targets (Juice Shop,
319
- crAPI) is the next step.
320
- - Compliance output (NIS2 [eu2022nis2]) is evidence toward a duty of care, not
321
- a certification.
370
+ (OWASP Foundation, n.d.-a) and the benchmarking approach of Antunes and Vieira
371
+ (2010, 2015) are the model for a fairer comparison. Scoring against labelled
372
+ third-party targets (Juice Shop, crAPI) is the next step.
373
+ - Compliance output for the NIS2 Directive (European Parliament and Council of
374
+ the European Union, 2022) is evidence toward a duty of care, not a
375
+ certification.
@@ -6,6 +6,7 @@ has the full flag list.
6
6
 
7
7
  | Command | Page | What it does |
8
8
  |---|---|---|
9
+ | `penthera`, `penthera init` | [init.md](init.md) | Set up in one command: detect, check, then hook, workflow and dashboard |
9
10
  | `penthera <url>`, `--repo .` | [scan.md](scan.md) | Scan a running app and its source: modes, profiles, outputs, exit codes, CI |
10
11
  | `penthera agents` | [agents.md](agents.md) | Audit skills, MCP servers, hooks, plugins and rule files |
11
12
  | `penthera deps` | [deps.md](deps.md) | What each package can do, the upgrade diff, typosquats, license policy |
@@ -14,7 +15,7 @@ has the full flag list.
14
15
  | `penthera hook` | [hook.md](hook.md) | Pre-commit hook for secrets, agent config and dependency changes |
15
16
  | GitHub Action | [action.md](action.md) | The capability diff as a pull-request comment, plus SARIF |
16
17
  | Agent Skill | [skill.md](skill.md) | Let Claude Code, Cursor and other agents drive Penthera |
17
- | `penthera ui` | [dashboard.md](../dashboard.md) | The local dashboard: posture, findings, history, evidence, and the fix loop from the page |
18
+ | `penthera ui` | [dashboard.md](../dashboard.md) | The local dashboard: one view with projects, findings, side cards, and the fix loop from the page |
18
19
 
19
20
  Compliance flags (`--framework nis2`, `--readiness`, `--cra`, `--aibom`, ...)
20
21
  are covered in [compliance-nis2.md](../compliance-nis2.md) and