penthera 1.4.0 → 1.6.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 +227 -0
- package/README.md +148 -575
- package/bin/scan.js +19 -0
- package/docs/commands/README.md +23 -0
- package/docs/commands/action.md +21 -0
- package/docs/commands/agents.md +38 -0
- package/docs/commands/deps.md +115 -0
- package/docs/commands/fix.md +53 -0
- package/docs/commands/hook.md +69 -0
- package/docs/commands/install.md +53 -0
- package/docs/commands/scan.md +100 -0
- package/docs/commands/skill.md +58 -0
- package/docs/compare/README.md +25 -0
- package/docs/compare/github.md +60 -0
- package/docs/compare/semgrep.md +54 -0
- package/docs/compare/snyk.md +62 -0
- package/docs/compare/socket.md +78 -0
- package/docs/compare/zap.md +59 -0
- package/docs/compliance-cra.md +141 -0
- package/docs/compliance-nis2.md +3 -1
- package/docs/dashboard.md +244 -0
- package/docs/evidence.md +8 -4
- package/docs/examples/github-actions-deps.yml +4 -4
- package/docs/examples/github-actions-scan.yml +4 -4
- package/docs/index.md +11 -2
- package/docs/internal-audit.md +83 -0
- package/docs/marketing.md +151 -0
- package/docs/plan.md +101 -0
- package/docs/privacy.md +38 -0
- package/docs/references.bib +10 -0
- package/docs/references.md +1 -0
- package/docs/research/socket-positioning-notes.md +183 -0
- package/docs/use-cases/README.md +14 -0
- package/docs/use-cases/agencies.md +71 -0
- package/docs/use-cases/ai-coding-teams.md +81 -0
- package/docs/use-cases/eu-sme-compliance.md +68 -0
- package/docs/use-cases/open-source-maintainers.md +75 -0
- package/docs/use-cases/solo-founder.md +65 -0
- package/lib/blackbox/email-dns.js +5 -0
- package/lib/compliance/cra.js +525 -0
- package/lib/compliance/questionnaire.js +4 -2
- package/lib/deps/capabilities.js +49 -12
- package/lib/deps/index.js +314 -30
- package/lib/deps/license.js +329 -0
- package/lib/deps/lockfile.js +29 -3
- package/lib/deps/popular-pypi.json +1 -0
- package/lib/deps/python/capabilities.js +447 -0
- package/lib/deps/python/index.js +234 -0
- package/lib/deps/python/lockfiles.js +359 -0
- package/lib/deps/python/source.js +396 -0
- package/lib/deps/python/toml.js +219 -0
- package/lib/deps/report.js +54 -6
- package/lib/deps/source.js +149 -24
- package/lib/deps/spdx.json +1 -0
- package/lib/deps/typosquat.js +24 -13
- package/lib/fix/apply.js +83 -19
- package/lib/hook/index.js +345 -0
- package/lib/hook/policy.js +62 -0
- package/lib/install/index.js +59 -18
- package/lib/install/policy.js +27 -7
- package/lib/jurisdictions/nl.json +9 -0
- package/lib/memory/repo-suppress.js +11 -3
- package/lib/references.json +77 -0
- package/lib/remediation/index.js +9 -0
- package/lib/retirejs.js +69 -17
- package/lib/rules/regex-guard.js +368 -0
- package/lib/templates.js +13 -6
- package/lib/tls.js +7 -0
- package/lib/whitebox/aibom.js +384 -0
- package/lib/whitebox/frameworks.js +8 -5
- package/lib/whitebox/sbom.js +45 -10
- package/lib/whitebox/secrets.js +31 -8
- package/package.json +8 -3
- package/skills/penthera/SKILL.md +55 -8
- package/src/cli/deps.js +81 -6
- package/src/cli/evidence.js +14 -4
- package/src/cli/hook.js +131 -0
- package/src/cli/install.js +14 -5
- package/src/cli/report-outputs.js +25 -2
- package/src/cli/ui.js +89 -0
- package/src/cli.js +81 -11
- package/src/report/audience.js +10 -10
- package/src/report/evidence.js +33 -14
- package/src/report/footer.js +11 -0
- package/src/report/markdown.js +6 -3
- package/src/report/md-escape.js +16 -0
- package/src/reporter.js +1 -0
- package/src/scan-url.js +5 -1
- package/src/ui/api/data.js +309 -0
- package/src/ui/api/demo.js +464 -0
- package/src/ui/api/routes.js +134 -0
- package/src/ui/api/runs.js +243 -0
- package/src/ui/api/summarize.js +451 -0
- package/src/ui/security.js +153 -0
- package/src/ui/server.js +186 -0
- package/src/ui/static/app.css +723 -0
- package/src/ui/static/favicon.svg +1 -0
- package/src/ui/static/index.html +57 -0
- package/src/ui/static/js/api.js +29 -0
- package/src/ui/static/js/app.js +138 -0
- package/src/ui/static/js/charts.js +207 -0
- package/src/ui/static/js/copy.js +79 -0
- package/src/ui/static/js/dom.js +120 -0
- package/src/ui/static/js/format.js +42 -0
- package/src/ui/static/js/theme.js +10 -0
- package/src/ui/static/js/typer.js +99 -0
- package/src/ui/static/js/views/ai.js +68 -0
- package/src/ui/static/js/views/deps.js +96 -0
- package/src/ui/static/js/views/evidence.js +115 -0
- package/src/ui/static/js/views/findings.js +165 -0
- package/src/ui/static/js/views/history.js +92 -0
- package/src/ui/static/js/views/overview.js +184 -0
- package/src/ui/static/js/views/run.js +349 -0
- package/src/ui/static/js/views/settings.js +67 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Penthera and Semgrep
|
|
2
|
+
|
|
3
|
+
*Last checked: 2026-10-19 against Semgrep's docs, GitHub and pricing page.*
|
|
4
|
+
|
|
5
|
+
## Use them together
|
|
6
|
+
|
|
7
|
+
[Semgrep](https://semgrep.dev) is a static analyser for your own code. The
|
|
8
|
+
Community Edition engine is open source (LGPL-2.1) and runs locally; the
|
|
9
|
+
commercial AppSec Platform adds cross-file analysis, supply-chain reachability,
|
|
10
|
+
secrets and AI triage ([CE vs platform](https://docs.semgrep.dev/semgrep-pro-vs-oss)).
|
|
11
|
+
Penthera's repo scan is narrower than Semgrep's. What Penthera adds is the rest
|
|
12
|
+
of the picture: the running app, what your dependencies can do, and your AI
|
|
13
|
+
tooling.
|
|
14
|
+
|
|
15
|
+
A reasonable setup: Semgrep on every pull request for code patterns, with your
|
|
16
|
+
own rules if you write them. Penthera for the lockfile, the preview URL and the
|
|
17
|
+
agent config.
|
|
18
|
+
|
|
19
|
+
## Side by side
|
|
20
|
+
|
|
21
|
+
| | Penthera | Semgrep |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| Your code | Route discovery, trust-boundary mapping and secrets for Next.js, Express, Hono, Fastify | Pattern-based analysis in many languages; CE works within a single file, the platform adds cross-file taint analysis ([CE vs platform](https://docs.semgrep.dev/semgrep-pro-vs-oss)) |
|
|
24
|
+
| Rules | Built in and readable; no rule language for users | A rule language plus 2,000+ community rules in the Registry ([repo](https://github.com/semgrep/semgrep)) |
|
|
25
|
+
| Dependencies | Capabilities, upgrade diff, typosquats, licenses (npm and Python) | Semgrep Supply Chain with reachability, on the platform |
|
|
26
|
+
| Running app | URL scan | No |
|
|
27
|
+
| AI tooling | `penthera agents` | No dedicated check |
|
|
28
|
+
| Network | None needed | CE with local rules sends no metrics by default; `--metrics=off` turns them off ([metrics](https://docs.semgrep.dev/metrics)) |
|
|
29
|
+
| Cost | Free, MIT | CE is free. Platform free for up to 10 contributors; Teams from $30 per contributor a month per product ([pricing](https://semgrep.dev/pricing)) |
|
|
30
|
+
|
|
31
|
+
## Where Semgrep goes further
|
|
32
|
+
|
|
33
|
+
- **Code analysis depth and breadth**: many languages, and dataflow across files
|
|
34
|
+
on the platform.
|
|
35
|
+
- **Your own rules.** If your team has patterns to ban, Semgrep's rule language
|
|
36
|
+
is the right tool. Penthera has no user rule language for code.
|
|
37
|
+
- **Reachability** for dependency vulnerabilities.
|
|
38
|
+
|
|
39
|
+
## Where Penthera adds something
|
|
40
|
+
|
|
41
|
+
- **Outside the source**: the running app, what packages do when installed, and
|
|
42
|
+
the agent config on your machine.
|
|
43
|
+
- **Fixes that are verified** by a re-scan on a local branch.
|
|
44
|
+
- **EU evidence** from the same runs.
|
|
45
|
+
|
|
46
|
+
## Run both
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
semgrep scan --config p/default --sarif -o semgrep.sarif
|
|
50
|
+
npx penthera http://localhost:3000 --repo . --sarif penthera.sarif
|
|
51
|
+
npx penthera deps --base origin/main
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
[All comparisons](README.md) · [Back to the README](../../README.md)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Penthera and Snyk
|
|
2
|
+
|
|
3
|
+
*Last checked: 2026-10-19 against Snyk's public docs, pricing page and GitHub.*
|
|
4
|
+
|
|
5
|
+
## Use them together
|
|
6
|
+
|
|
7
|
+
[Snyk](https://snyk.io) is a developer security platform built around a curated
|
|
8
|
+
vulnerability database: it tells you which of your dependencies, containers and
|
|
9
|
+
infrastructure files have known issues, across many languages, and opens fix
|
|
10
|
+
pull requests. Penthera asks different questions: what can a package do (not
|
|
11
|
+
only which CVEs it has), how does the running app behave, and what is in your
|
|
12
|
+
AI tooling config. It does this offline and without an account.
|
|
13
|
+
|
|
14
|
+
A reasonable setup: Snyk for known-vulnerability coverage across your stack.
|
|
15
|
+
Penthera for the behaviour diff on lockfile changes, the scan of your preview
|
|
16
|
+
URL before a deploy, and the agent-config audit.
|
|
17
|
+
|
|
18
|
+
## Side by side
|
|
19
|
+
|
|
20
|
+
| | Penthera | Snyk |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| Dependencies | What each npm and Python package can do (install scripts, shell, network, env, obfuscation), what an upgrade added, typosquats, licenses | Known vulnerabilities and licenses across 13+ package ecosystems ([supported languages](https://docs.snyk.io/supported-languages/supported-languages-package-managers-and-frameworks)) |
|
|
23
|
+
| Your code | Route discovery, trust boundaries and secrets for JS/TS frameworks | Snyk Code static analysis in 16 languages ([supported languages](https://docs.snyk.io/supported-languages/supported-languages-package-managers-and-frameworks)) |
|
|
24
|
+
| Running app | URL scan (headers, TLS, CORS, auth, JWT, IDOR, OAuth, OpenAPI; opt-in injection and fuzzing) | Snyk API & Web, a DAST product on Enterprise plans ([plans](https://snyk.io/plans/)) |
|
|
25
|
+
| Containers, IaC | No | Yes ([CLI](https://docs.snyk.io/developer-tools/snyk-cli)) |
|
|
26
|
+
| AI tooling | `penthera agents`: skills, MCP servers, hooks, permissions, plugins, rule files, checked locally | Snyk Agent Scan: MCP servers and skills, sends component metadata to Snyk's API and needs a token ([agent-scan](https://github.com/snyk/agent-scan)) |
|
|
27
|
+
| Account | None | Required for the CLI ([authenticate](https://docs.snyk.io/developer-tools/snyk-cli/authenticate-to-use-the-cli)) |
|
|
28
|
+
| Fixes | Deterministic recipes as local diffs, re-scanned to verify; never pushes | Fix pull requests through SCM integrations ([fix PRs](https://docs.snyk.io/scan-with-snyk/pull-requests/snyk-fix-pull-or-merge-requests)) |
|
|
29
|
+
| Editor | Through your coding agent (Agent Skill) | Plugins for VS Code, JetBrains, Visual Studio, Eclipse ([IDE](https://docs.snyk.io/developer-tools/snyk-ide-plugins-and-extensions)) |
|
|
30
|
+
| Licence | MIT | CLI is Apache-2.0 ([repo](https://github.com/snyk/cli)); the platform is commercial |
|
|
31
|
+
| Cost | Free | Free plan with 5 projects and 100 Snyk Code tests a month; Team from $25 a month ([plans](https://snyk.io/plans/)) |
|
|
32
|
+
|
|
33
|
+
## Where Snyk goes further
|
|
34
|
+
|
|
35
|
+
- **Curated vulnerability data** across many languages, with advisories written
|
|
36
|
+
and maintained by a research team. Penthera does not track CVEs for your
|
|
37
|
+
dependencies beyond the vendored Retire.js database for front-end scripts.
|
|
38
|
+
- **Breadth**: containers, infrastructure as code, many more languages.
|
|
39
|
+
- **Reachability analysis** to cut a CVE list down to what you call.
|
|
40
|
+
- **Organisation features**: dashboards, policies across many repos, reporting.
|
|
41
|
+
|
|
42
|
+
## Where Penthera adds something
|
|
43
|
+
|
|
44
|
+
- **Behaviour, not only known issues.** A new install script or a package that
|
|
45
|
+
suddenly reads your whole environment shows up even when no CVE exists yet.
|
|
46
|
+
- **The running app**, free, on localhost.
|
|
47
|
+
- **Fully local.** No account, no API calls, nothing about your code leaves the
|
|
48
|
+
machine. The AI-tooling audit is local too.
|
|
49
|
+
- **EU evidence**: NIS2 readiness, CRA report drafts, SBOM and AI-BOM, and a
|
|
50
|
+
signable evidence bundle.
|
|
51
|
+
|
|
52
|
+
## Run both
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
snyk test # known vulnerabilities in dependencies
|
|
56
|
+
npx penthera deps --base origin/main # what the new packages can do
|
|
57
|
+
npx penthera http://localhost:3000 --repo .
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Both write SARIF, so both can upload to GitHub code scanning.
|
|
61
|
+
|
|
62
|
+
[All comparisons](README.md) · [Back to the README](../../README.md)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Penthera and Socket
|
|
2
|
+
|
|
3
|
+
*Last checked: 2026-10-19 against Socket's public docs and pricing page.*
|
|
4
|
+
|
|
5
|
+
## Use them together
|
|
6
|
+
|
|
7
|
+
[Socket](https://socket.dev) watches the open-source registries for malicious and
|
|
8
|
+
risky packages and tells you about them in pull requests, in your editor and at
|
|
9
|
+
install time. Penthera runs on your machine and checks the app you built, the
|
|
10
|
+
packages already in your lockfile, and the AI tooling you build it with.
|
|
11
|
+
|
|
12
|
+
A reasonable setup: Socket's GitHub app or firewall on every dependency change,
|
|
13
|
+
because it watches new releases across the registries and Penthera does
|
|
14
|
+
not. Penthera before each deploy, for the app scan, the agent-config audit
|
|
15
|
+
and the evidence, and anywhere a network call or an account is not an option.
|
|
16
|
+
|
|
17
|
+
## Side by side
|
|
18
|
+
|
|
19
|
+
| | Penthera | Socket |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| Main question | Is the thing I am about to ship safe, and can I prove it? | Is this package safe to depend on? |
|
|
22
|
+
| Scope | Your running app (URL scan), your source (repo scan), your dependencies, your AI tooling (skills, MCP, hooks), fixes, NIS2 and CRA evidence | Packages across many ecosystems, plus browser extensions and AI models ([language support](https://docs.socket.dev/docs/language-support)) |
|
|
23
|
+
| Ecosystems for dependencies | npm and Python | JS/TS, Python, Go, Java, Ruby, .NET, Rust and more ([language support](https://docs.socket.dev/docs/language-support)) |
|
|
24
|
+
| How it decides | Deterministic rules in the repo, with `file:line` evidence and a confidence label | Static analysis followed by an LLM stage, with researchers confirming detections ([AI alert](https://socket.dev/alerts/gptMalware)) |
|
|
25
|
+
| Threat intelligence | None beyond what ships in a release | Registry-wide and continuously updated |
|
|
26
|
+
| Network | None needed; `--offline` limits traffic to the target you named | The CLI and firewall query Socket's API ([CLI](https://github.com/SocketDev/socket-cli), [firewall](https://docs.socket.dev/docs/socket-firewall-overview)) |
|
|
27
|
+
| Account | None | API token for the CLI; the firewall's free wrapper mode needs no key ([firewall](https://docs.socket.dev/docs/socket-firewall-overview)) |
|
|
28
|
+
| Install-time guard | `penthera install`: reviews capabilities and install scripts before any script runs (npm) | Socket Firewall (`sfw`): blocks known-malicious packages for npm, yarn, pnpm, pip, uv and cargo in free mode |
|
|
29
|
+
| Pull requests | GitHub Action that comments the capability diff | GitHub app that comments on risky dependency changes ([docs](https://docs.socket.dev/docs/socket-for-github)) |
|
|
30
|
+
| AI tooling | Audits the skills, MCP servers, hooks, permissions and plugins already on disk | An MCP server agents can use to look up package scores ([MCP guide](https://docs.socket.dev/docs/guide-to-socket-mcp)); firewall coverage for agent skills and AI models as downloads ([firewall](https://socket.dev/features/firewall)) |
|
|
31
|
+
| App security | URL and repo scans, fix recipes | Not its focus; SAST and secrets are on the Enterprise plan ([pricing](https://socket.dev/pricing)) |
|
|
32
|
+
| SBOM | CycloneDX SBOM and AI-BOM, free | Business plan and up ([pricing](https://socket.dev/pricing)) |
|
|
33
|
+
| Licence | MIT | `socket` CLI and MCP server MIT; `sfw` under PolyForm Shield 1.0.0 (source-available) ([sfw-free](https://github.com/SocketDev/sfw-free)) |
|
|
34
|
+
| Cost | Free | Free plan (1 seat, 1,000 scans a month); free Business plan for OSI-licensed public projects ([announcement](https://socket.dev/blog/free-business-plan-upgrades-for-open-source)); paid seats from $25 a month ([pricing](https://socket.dev/pricing)) |
|
|
35
|
+
|
|
36
|
+
## Where Socket goes further
|
|
37
|
+
|
|
38
|
+
- **It sees the whole registry.** A freshly published package with a
|
|
39
|
+
credential stealer in it can be flagged by Socket before you install it.
|
|
40
|
+
Penthera only sees what is in front of it, with rules from its last release.
|
|
41
|
+
- **More ecosystems.** Penthera's dependency checks cover npm and Python today,
|
|
42
|
+
and its install firewall covers npm only.
|
|
43
|
+
- **Human research.** Socket's researchers confirm and publish malware
|
|
44
|
+
findings. Penthera has no threat-research team.
|
|
45
|
+
- **Reachability** on paid plans, which narrows a long CVE list to the code paths
|
|
46
|
+
you call.
|
|
47
|
+
|
|
48
|
+
## Where Penthera adds something
|
|
49
|
+
|
|
50
|
+
- **Your app, not only its packages.** Headers, auth, IDOR, OAuth, OpenAPI,
|
|
51
|
+
secrets in source, and fixes that are re-scanned to prove they worked.
|
|
52
|
+
- **The AI tooling on your machine.** `penthera agents --home` reads your Claude
|
|
53
|
+
Code, Cursor and MCP config and flags hidden instructions, unpinned servers and
|
|
54
|
+
over-broad permissions.
|
|
55
|
+
- **Offline and account-free**, which matters on air-gapped machines, in some
|
|
56
|
+
public-sector work, and for anyone who cannot send a dependency list to a
|
|
57
|
+
vendor.
|
|
58
|
+
- **Readable verdicts.** Every finding points at a rule in this repository.
|
|
59
|
+
|
|
60
|
+
## A note on AI verdicts
|
|
61
|
+
|
|
62
|
+
Socket's AI scanner once flagged Penthera itself as malware. That is an
|
|
63
|
+
understandable call: Penthera's test suite contains real attack payloads,
|
|
64
|
+
because a security scanner has to be tested against them. It is also a fair
|
|
65
|
+
illustration of the trade-off. An AI stage catches novel malware that no rule
|
|
66
|
+
anticipated, and it can misread intent. Deterministic rules miss what they were
|
|
67
|
+
not written for, and they always tell you exactly why they fired. The two
|
|
68
|
+
approaches cover each other's gaps, which is a good reason to run both.
|
|
69
|
+
|
|
70
|
+
## Run both
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
sfw npm install # Socket Firewall: block known-bad packages at install
|
|
74
|
+
npx penthera deps --base origin/main # what the new packages can do, offline
|
|
75
|
+
npx penthera agents --home # your AI tooling
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
[All comparisons](README.md) · [Back to the README](../../README.md)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Penthera and OWASP ZAP
|
|
2
|
+
|
|
3
|
+
*Last checked: 2026-10-19 against zaproxy.org and the ZAP GitHub repositories.*
|
|
4
|
+
|
|
5
|
+
## Use them together
|
|
6
|
+
|
|
7
|
+
[ZAP](https://www.zaproxy.org) is the long-standing open-source dynamic scanner
|
|
8
|
+
for web apps: a proxy, spiders, passive and active scan rules, scripting, and an
|
|
9
|
+
automation framework. Since September 2024 it is branded ZAP by Checkmarx and
|
|
10
|
+
remains Apache 2.0 ([announcement](https://www.zaproxy.org/blog/2024-09-24-zap-has-joined-forces-with-checkmarx/)).
|
|
11
|
+
Penthera's URL scan covers a smaller, opinionated set of checks, and pairs them
|
|
12
|
+
with the source code, your dependencies and your AI tooling.
|
|
13
|
+
|
|
14
|
+
A reasonable setup: Penthera as the quick first pass on every preview URL,
|
|
15
|
+
with source context and fixes. ZAP for deeper dynamic testing, manual
|
|
16
|
+
exploration through its proxy, and anything that needs a logged-in browser crawl.
|
|
17
|
+
|
|
18
|
+
## Side by side
|
|
19
|
+
|
|
20
|
+
| | Penthera | ZAP |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| Dynamic testing | Headers, TLS, CORS, cookies, auth hardening, JWT, IDOR, OAuth, OpenAPI probes; injection and fuzzing are opt-in | Passive and active scan rules, spider and AJAX spider ([features](https://www.zaproxy.org/docs/desktop/start/features/), [AJAX spider](https://www.zaproxy.org/docs/desktop/addons/ajax-spider/)) |
|
|
23
|
+
| API definitions | OpenAPI and FastAPI | OpenAPI, SOAP and GraphQL ([API scan](https://www.zaproxy.org/docs/docker/api-scan/)) |
|
|
24
|
+
| Manual testing | No | Intercepting proxy and desktop UI |
|
|
25
|
+
| Source code | Repo scan in the same run (`--repo .`) maps routes and finds secrets | No |
|
|
26
|
+
| Dependencies, AI tooling | Yes | No |
|
|
27
|
+
| Fixes | Framework-aware fix recipes, re-scanned to verify | Reports alerts |
|
|
28
|
+
| Automation | CLI, GitHub Action, SARIF | YAML Automation Framework, Docker packaged scans, the ZAP Baseline Scan action ([automate](https://www.zaproxy.org/docs/automate/)) |
|
|
29
|
+
| Runtime | Node.js 22+ | Java 17+, or Docker ([download](https://www.zaproxy.org/download/)) |
|
|
30
|
+
| Licence | MIT | Apache 2.0 |
|
|
31
|
+
|
|
32
|
+
## Where ZAP goes further
|
|
33
|
+
|
|
34
|
+
- **Depth of dynamic testing**: many more active scan rules, a mature crawler
|
|
35
|
+
for JavaScript-heavy apps, and years of tuning.
|
|
36
|
+
- **Manual work**: the intercepting proxy lets a person explore and replay.
|
|
37
|
+
- **Authentication**: browser-based, scripted and OAuth2 logins in the
|
|
38
|
+
automation framework ([automation framework](https://www.zaproxy.org/docs/automate/automation-framework/)).
|
|
39
|
+
Penthera takes a cookie or bearer token.
|
|
40
|
+
- **Community**: a large add-on ecosystem and documentation.
|
|
41
|
+
|
|
42
|
+
## Where Penthera adds something
|
|
43
|
+
|
|
44
|
+
- **Black box and white box together.** A URL finding can point at the route
|
|
45
|
+
handler in your repo, and the repo scan finds routes the crawler never saw.
|
|
46
|
+
- **Fixes**, applied as diffs on a local branch and re-scanned.
|
|
47
|
+
- **Beyond the app**: dependency capabilities, AI-tooling audit, NIS2 and CRA
|
|
48
|
+
evidence.
|
|
49
|
+
- **A confidence label on every finding**, so a heuristic match never reads as a
|
|
50
|
+
confirmed vulnerability.
|
|
51
|
+
|
|
52
|
+
## Run both
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npx penthera http://localhost:3000 --repo . --sarif penthera.sarif
|
|
56
|
+
docker run -t ghcr.io/zaproxy/zaproxy:stable zap-baseline.py -t http://host.docker.internal:3000
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
[All comparisons](README.md) · [Back to the README](../../README.md)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Compliance: the Cyber Resilience Act (CRA)
|
|
2
|
+
|
|
3
|
+
Back to the [README](../README.md). NIS2 lives in
|
|
4
|
+
[compliance-nis2.md](compliance-nis2.md).
|
|
5
|
+
|
|
6
|
+
The Cyber Resilience Act, [Regulation (EU) 2024/2847](https://eur-lex.europa.eu/eli/reg/2024/2847/oj/eng),
|
|
7
|
+
puts security duties on manufacturers of products with digital elements, which
|
|
8
|
+
includes software you sell or make available in the EU. Most of it applies from
|
|
9
|
+
11 December 2027. The reporting duty in **Article 14 has applied since
|
|
10
|
+
11 September 2026** (Art. 71(2)), and it also covers products placed on the
|
|
11
|
+
market before December 2027 (Art. 69(3)).
|
|
12
|
+
|
|
13
|
+
Penthera helps with two pieces of CRA evidence, offline:
|
|
14
|
+
|
|
15
|
+
| Command | What you get |
|
|
16
|
+
|---------|--------------|
|
|
17
|
+
| `--cra-init cra.json` then `--cra cra.json` | Article 14 timeline with real due dates, overdue flags, and drafts of every report |
|
|
18
|
+
| `--repo . --aibom aibom.cdx.json` | CycloneDX 1.6 AI-BOM: AI SDKs, models referenced in code, MCP servers, skills, prompt files |
|
|
19
|
+
|
|
20
|
+
Penthera does not make you CRA compliant and does not certify anything. The
|
|
21
|
+
drafts are not the ENISA platform's official form, and none of this is legal
|
|
22
|
+
advice.
|
|
23
|
+
|
|
24
|
+
## Article 14 reporting helper
|
|
25
|
+
|
|
26
|
+
### What the regulation asks
|
|
27
|
+
|
|
28
|
+
Checked on 2026-10-19 against the Official Journal text and the
|
|
29
|
+
[ENISA Single Reporting Platform (SRP) FAQ](https://www.enisa.europa.eu/topics/product-security/vulnerability-services/eu-incident-response-and-cyber-crisis-management/single-reporting-platform-srp/frequently-asked-questions).
|
|
30
|
+
|
|
31
|
+
| | Actively exploited vulnerability (Art. 14(1)-(2)) | Severe incident (Art. 14(3)-(5)) |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| Early warning | within 24 hours of becoming aware, with the Member States where the product is available | within 24 hours, including whether it is suspected to be caused by unlawful or malicious acts, plus Member States |
|
|
34
|
+
| Notification | within 72 hours: the product, the general nature of the exploit and the vulnerability, corrective or mitigating measures taken and ones users can take, how sensitive the information is | within 72 hours: nature of the incident, an initial assessment, measures taken and ones users can take, sensitivity |
|
|
35
|
+
| Final report | no later than **14 days after a corrective or mitigating measure is available**: description with severity and impact, any malicious actor, details of the security update | within **one month after the incident notification**: detailed description with severity and impact, type of threat or root cause, applied and ongoing mitigations |
|
|
36
|
+
|
|
37
|
+
- **Where to send it.** Through the [ENISA Single Reporting Platform](https://portal.cra-srp.enisa.europa.eu/),
|
|
38
|
+
using the end-point of the CSIRT designated as coordinator in the Member State
|
|
39
|
+
of your main establishment. ENISA receives it at the same time (Art. 14(1),
|
|
40
|
+
14(3), 14(7)). For the Netherlands that CSIRT is **NCSC-NL**, per ENISA's
|
|
41
|
+
[list of CSIRTs designated as coordinators](https://www.enisa.europa.eu/topics/product-security/vulnerability-services/eu-incident-response-and-cyber-crisis-management/single-reporting-platform-srp/list-of-csirts-designated-as-coordinators).
|
|
42
|
+
- **Inform your users.** After becoming aware, inform impacted users (and where
|
|
43
|
+
appropriate all users), with mitigations they can deploy, where appropriate
|
|
44
|
+
in a machine-readable format (Art. 14(8)).
|
|
45
|
+
- **One notification** per vulnerability or incident, even across subsidiaries
|
|
46
|
+
(ENISA SRP FAQ). The CSIRT may ask for an intermediate report (Art. 14(6)).
|
|
47
|
+
- An *actively exploited vulnerability* is one with reliable evidence that a
|
|
48
|
+
malicious actor exploited it without the system owner's permission (Art. 3(42)).
|
|
49
|
+
An incident is *severe* if it can harm the availability, authenticity,
|
|
50
|
+
integrity or confidentiality of sensitive or important data or functions, or
|
|
51
|
+
can lead to malicious code in the product or a user's systems (Art. 14(5)).
|
|
52
|
+
|
|
53
|
+
### Use it
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
penthera --cra-init cra.json # set type ("vulnerability" or "incident") and aware_at
|
|
57
|
+
penthera --cra cra.json # writes cra-reports.md and prints the deadlines
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`cra-reports.md` holds the timeline (UTC and your local time), a status per
|
|
61
|
+
report (`due in 21h 30m`, `submitted`, `submitted late`, `OVERDUE`,
|
|
62
|
+
`waiting for a fix`), a draft of each report with `NEEDS INPUT` for every fact
|
|
63
|
+
still missing, and a draft user advisory for Art. 14(8). Record what you've sent
|
|
64
|
+
in `submitted.early_warning` / `submitted.notification` / `submitted.final_report`
|
|
65
|
+
and re-run; for a severe incident the final report then counts from the real
|
|
66
|
+
submission time instead of the 72-hour deadline.
|
|
67
|
+
|
|
68
|
+
**Prefill from your scan and SBOM.** Name the affected dependency in
|
|
69
|
+
`component.name` and point `prefill` at Penthera output (paths relative to
|
|
70
|
+
`cra.json`):
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"type": "vulnerability",
|
|
75
|
+
"aware_at": "2026-10-24T09:00:00+02:00",
|
|
76
|
+
"component": { "name": "jquery" },
|
|
77
|
+
"prefill": { "scan": "scan.json", "sbom": "sbom.cdx.json" }
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
penthera https://staging.example.com --repo . --sbom sbom.cdx.json -o scan.json
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
From the SBOM it fills the product name and version and the component's version
|
|
86
|
+
and purl; from the scan, matching CVE ids, the scanner severity, and the finding
|
|
87
|
+
titles. Prefilled values are marked *verify* in the draft, and anything you wrote
|
|
88
|
+
yourself is never overwritten. A full example lives in `tests/fixtures/cra/`.
|
|
89
|
+
|
|
90
|
+
### How the deadlines are counted
|
|
91
|
+
|
|
92
|
+
- **Hours are elapsed hours** from `aware_at`. If the clocks change in between,
|
|
93
|
+
the local due time shifts (24 hours from 09:00 CEST on 24 October 2026 is
|
|
94
|
+
08:00 CET on 25 October).
|
|
95
|
+
- **Days and months are calendar periods** in your `timezone` (default
|
|
96
|
+
`Europe/Amsterdam`), ending at the same clock time. One month from 31 January
|
|
97
|
+
ends on 28 (or 29) February, following
|
|
98
|
+
[Regulation 1182/71](https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:31971R1182) Art. 3(2)(c).
|
|
99
|
+
- A timestamp without an offset is read in `timezone`. Use ISO 8601.
|
|
100
|
+
- This is the **strict reading**. Regulation 1182/71 can give a little more
|
|
101
|
+
time (a period runs to the end of the hour or day, and a days or months period
|
|
102
|
+
that ends on a weekend or public holiday moves to the next working day).
|
|
103
|
+
Don't plan on that; report early.
|
|
104
|
+
|
|
105
|
+
The helper warns if `aware_at` is before 11 September 2026, if
|
|
106
|
+
`main_establishment` is not the Netherlands (so NCSC-NL is not your CSIRT), and
|
|
107
|
+
if the type or time zone is unknown.
|
|
108
|
+
|
|
109
|
+
## AI-BOM (CycloneDX 1.6)
|
|
110
|
+
|
|
111
|
+
Customers and auditors increasingly ask what AI a product contains: which
|
|
112
|
+
providers get your data, which models, which agent tooling. `--aibom`
|
|
113
|
+
inventories it from the repo, offline:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
penthera --repo . --aibom aibom.cdx.json
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
| Found | How | CycloneDX |
|
|
120
|
+
|-------|-----|-----------|
|
|
121
|
+
| AI SDKs: `openai`, `@anthropic-ai/sdk`, `@google/genai`, `ai` / `@ai-sdk/*`, `langchain` / `@langchain/*`, `llamaindex`, `ollama`, `@huggingface/transformers`; on PyPI `anthropic`, `transformers`, `torch`, `langchain-*`, `llama-index-*`, `litellm`, `mcp` and others | lockfile, `package.json`, `requirements.txt`, `pyproject.toml` | `library` with purl |
|
|
122
|
+
| Models: `claude-*`, `gpt-*`, `o3`, `text-embedding-*`, `gemini-*`, `gemma*`, `llama*`, `mistral-*`, `deepseek-*`, `qwen*`, `phi-*`, `grok-*`, Hugging Face ids (`meta-llama/Llama-3.1-8B-Instruct`) | whole string literals in code and `model:` keys in YAML/TOML; HF ids only for known orgs or next to a loader call | `machine-learning-model` with supplier, `modelCard` stub, `evidence.occurrences` (file and line) |
|
|
123
|
+
| MCP servers | `lib/agents/discover.js` (`.mcp.json`, `.cursor/`, `.vscode/mcp.json`, ...) | `services` with transport, package, endpoint and trust boundary; env var *names* only, never values or args |
|
|
124
|
+
| Agent Skills | `SKILL.md` folders | `data` with SHA-256 |
|
|
125
|
+
| Prompt files | `*.prompt`, `*.prompty`, `*.prompt.md`, anything under a `prompts/` folder | `data` with SHA-256 |
|
|
126
|
+
|
|
127
|
+
Every item hangs off the root component in `dependencies`. The BOM is only the
|
|
128
|
+
AI slice; use `--sbom` for all dependencies.
|
|
129
|
+
|
|
130
|
+
Spec references: the [CycloneDX 1.6 JSON reference](https://cyclonedx.org/docs/1.6/json/),
|
|
131
|
+
the [ML-BOM capability page](https://cyclonedx.org/capabilities/mlbom/), and the
|
|
132
|
+
[official schema](https://github.com/CycloneDX/specification/blob/master/schema/bom-1.6.schema.json).
|
|
133
|
+
That schema (with its SPDX and JSF dependencies) is vendored in
|
|
134
|
+
`tests/fixtures/cyclonedx/`, and the tests validate every generated AI-BOM
|
|
135
|
+
against it without network. Penthera emits 1.6 (ML-BOM first appeared in 1.5);
|
|
136
|
+
CycloneDX 1.7 is also published and is a later upgrade.
|
|
137
|
+
|
|
138
|
+
**Limits.** A model string in code means the model is referenced, not that it
|
|
139
|
+
runs in production; the evidence lines let a reviewer check. Model ids built at
|
|
140
|
+
runtime (`` `claude-${tier}` ``) are not detected. The `modelCard` is a stub:
|
|
141
|
+
fill in task, datasets and considerations from the provider's model card.
|
package/docs/compliance-nis2.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Compliance: NIS2 and the cyberwetgeving
|
|
2
2
|
|
|
3
|
-
Back to the [README](../README.md).
|
|
3
|
+
Back to the [README](../README.md). Shipping a product? The Cyber Resilience
|
|
4
|
+
Act's Article 14 reporting helper and the AI-BOM are in
|
|
5
|
+
[compliance-cra.md](compliance-cra.md).
|
|
4
6
|
|
|
5
7
|
The EU NIS2 directive and its national transpositions (the Cyberbeveiligingswet
|
|
6
8
|
in the Netherlands, the NIS2-wet in Belgium) put a duty of care, the *zorgplicht*,
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# The local dashboard: `penthera ui`
|
|
2
|
+
|
|
3
|
+
`penthera ui` opens a dashboard in your browser for what Penthera knows about
|
|
4
|
+
your projects: where each one stands, what each finding means, what changed
|
|
5
|
+
since the last scan, your dependencies and AI tooling, and evidence for an
|
|
6
|
+
auditor. It can also run scans and the fix loop for you, stopping at every
|
|
7
|
+
diff. It runs on `127.0.0.1` only, reads only the folders you give it and
|
|
8
|
+
`~/.penthera`, and never contacts the network.
|
|
9
|
+
|
|
10
|
+
| Dark | Light |
|
|
11
|
+
|---|---|
|
|
12
|
+
|  |  |
|
|
13
|
+
|
|
14
|
+
## Start it
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
penthera ui --open # current folder, reports in ./reports
|
|
18
|
+
penthera ui --project ~/code/shop --project ~/code/api --reports ~/code/shop/reports
|
|
19
|
+
penthera ui --demo # fake data, nothing read from disk
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
| Option | Default | What it does |
|
|
23
|
+
|--------|---------|--------------|
|
|
24
|
+
| `--port <n>` | `0` (random free port) | Port on 127.0.0.1 |
|
|
25
|
+
| `--open` | off | Open the one-time URL in your browser |
|
|
26
|
+
| `--project <dir>` | the current folder | A folder the dashboard may read and run in. Repeat for more |
|
|
27
|
+
| `--reports <dir>` | `<first project>/reports` | Where report JSON is read from, and where runs started here write theirs |
|
|
28
|
+
| `--demo` | off | Realistic fake data and a scripted fix loop. For a first look, screenshots and docs |
|
|
29
|
+
|
|
30
|
+
It prints a URL with a one-time token. Open it once: the token is swapped for
|
|
31
|
+
a session cookie and stops working, so a second browser (or a link that leaked
|
|
32
|
+
into history) gets a 403. Restart `penthera ui` for a new link. Ctrl-C stops
|
|
33
|
+
the server.
|
|
34
|
+
|
|
35
|
+
## User stories
|
|
36
|
+
|
|
37
|
+
Each story names who it is for, what they want and why. Each one has a
|
|
38
|
+
feature in the dashboard and a screenshot from `penthera ui --demo`.
|
|
39
|
+
|
|
40
|
+
**1. First run, nothing scanned yet.** *As a solo founder the week before
|
|
41
|
+
launch, I want the dashboard to tell me what to do first when there is no
|
|
42
|
+
data yet, so that I am not staring at empty charts.* The overview turns into
|
|
43
|
+
a three-step start: scan your app, check your dependencies, audit your AI
|
|
44
|
+
tooling. Each step opens Run with the right mode and your project folder
|
|
45
|
+
filled in.
|
|
46
|
+
|
|
47
|
+

|
|
48
|
+
|
|
49
|
+
**2. Run a scan from the UI.** *As a developer who does not live in the
|
|
50
|
+
terminal, I want to start a scan from the page and watch it work, so that I
|
|
51
|
+
know it ran and where the report went.* Run has four modes: scan app, check
|
|
52
|
+
dependencies, audit AI tooling, fix loop. A URL that is not on this machine
|
|
53
|
+
needs its hostname typed back first. Output streams into a terminal window;
|
|
54
|
+
when it finishes, "What next?" offers the obvious next steps.
|
|
55
|
+
|
|
56
|
+

|
|
57
|
+
|
|
58
|
+
**3. Let the agent fix things, one approved diff at a time.** *As a founder
|
|
59
|
+
with no security engineer, I want Penthera to propose fixes and apply only the
|
|
60
|
+
ones I approve, so that nothing changes in my code without me seeing it.* The
|
|
61
|
+
fix loop stops at every diff with a dialog: the recipe, the files, what the
|
|
62
|
+
fix closes, what memory knows about this recipe, and the diff itself. Apply
|
|
63
|
+
(`y`), Skip (`n`) or Stop the loop (`q`). Verified fixes are committed on a
|
|
64
|
+
local branch; failed ones are reverted. Nothing is pushed.
|
|
65
|
+
|
|
66
|
+

|
|
67
|
+
|
|
68
|
+
**4. Understand one finding.** *As a product owner who is not a security
|
|
69
|
+
expert, I want one finding explained in plain words, so that I can decide
|
|
70
|
+
whether it matters today.* The detail panel opens with "In plain words": how
|
|
71
|
+
serious it is, how sure Penthera is (and what that confidence level means),
|
|
72
|
+
what to do, and the OWASP mapping. Below it: what was seen, the evidence, the
|
|
73
|
+
sources, and the exact fix diff.
|
|
74
|
+
|
|
75
|
+

|
|
76
|
+
|
|
77
|
+
**5. Compare over time.** *As a tech lead after a release, I want to compare
|
|
78
|
+
two scans of the same project, so that I can see what got fixed and what is
|
|
79
|
+
new.* History picks the most interesting project by default, compares the
|
|
80
|
+
previous scan with the latest (or any two you choose), and lists new, fixed
|
|
81
|
+
and still-open findings in three columns. Below them, a timeline draws every
|
|
82
|
+
finding as a bar across the scans (S1, S2, ...): hatched while it is still
|
|
83
|
+
open, an outline once it was fixed.
|
|
84
|
+
|
|
85
|
+

|
|
86
|
+
|
|
87
|
+
**6. Export evidence for an auditor.** *As the person who answers the NIS2
|
|
88
|
+
questionnaire, I want a package an auditor can check without trusting me, so
|
|
89
|
+
that the evidence holds up.* Evidence creates a bundle from the latest scan
|
|
90
|
+
of a project (JSON, Markdown, SARIF, the auditor, owner and developer reports,
|
|
91
|
+
and a manifest with a SHA-256 per file), verifies it straight away, and lets
|
|
92
|
+
you download the auditor report as Markdown.
|
|
93
|
+
|
|
94
|
+

|
|
95
|
+
|
|
96
|
+
**7. Check what a dependency change can do.** *As a developer reviewing a
|
|
97
|
+
pull request that bumps the lockfile, I want to see which packages gained new
|
|
98
|
+
capabilities, so that I catch a malicious update before it runs.* Dependencies
|
|
99
|
+
shows the capabilities in the tree, the capability diff against your base,
|
|
100
|
+
typosquats, and every install firewall decision.
|
|
101
|
+
|
|
102
|
+

|
|
103
|
+
|
|
104
|
+
**8. Trust my AI tooling.** *As someone who installs skills and MCP servers
|
|
105
|
+
into Claude Code and Cursor, I want to know whether any of them hide
|
|
106
|
+
instructions or changed since I reviewed them, so that my agent is not working
|
|
107
|
+
for someone else.* AI tooling shows the A to F grade, hidden content with the
|
|
108
|
+
decoded text, and drift against `penthera.lock`.
|
|
109
|
+
|
|
110
|
+

|
|
111
|
+
|
|
112
|
+
**9. Know where to start this week.** *As a solo founder on a Monday morning,
|
|
113
|
+
I want one place that says what to fix first and what changed since the last
|
|
114
|
+
scan, so that I do not have to read every report.* The overview opens with a
|
|
115
|
+
"This week" window: fix first (every critical and high), new since the last
|
|
116
|
+
scan, and fixed since the last scan, across all projects. Each line opens the
|
|
117
|
+
finding.
|
|
118
|
+
|
|
119
|
+

|
|
120
|
+
|
|
121
|
+
**10. Work in daylight.** *As someone who reads reports on a bright screen, I
|
|
122
|
+
want a light theme, so that the dashboard is comfortable outside a dark room.*
|
|
123
|
+
The `◐` button in the menu bar (and Settings) switches between the black
|
|
124
|
+
terminal and the white paper theme. The first visit follows your system
|
|
125
|
+
setting; the choice is remembered in this browser.
|
|
126
|
+
|
|
127
|
+
| Narrow, dark | Narrow, light |
|
|
128
|
+
|---|---|
|
|
129
|
+
| <img src="../assets/dashboard/narrow-dark.jpg" alt="Overview at 390px, dark" width="280"> | <img src="../assets/dashboard/narrow-light.jpg" alt="History at 390px, light" width="280"> |
|
|
130
|
+
|
|
131
|
+
## Where the data comes from
|
|
132
|
+
|
|
133
|
+
| Screen | Source |
|
|
134
|
+
|--------|--------|
|
|
135
|
+
| Overview | The latest scan report per target in the reports folder, plus trend and time to fix from local memory |
|
|
136
|
+
| Findings | The same reports. The fix preview runs the fix recipes against the project folder, read-only |
|
|
137
|
+
| Run | Live runs started from this page; past `loopRun` files; memory stats |
|
|
138
|
+
| History | Every scan report of one project in the reports folder |
|
|
139
|
+
| Dependencies | `penthera deps -o reports/deps.json` and `penthera install <pkg> --dry-run --json > reports/install.json` (or Run → Check dependencies) |
|
|
140
|
+
| AI tooling | `penthera agents . -o reports/agents.json` (or Run → Audit AI tooling) |
|
|
141
|
+
| Evidence | Bundles below the reports folder, written with `--evidence` or from this screen |
|
|
142
|
+
| Settings | Theme, egress mode for scans started here, data locations, memory chain status |
|
|
143
|
+
|
|
144
|
+
The reports folder is read one level deep for `*.json` (anything that is not
|
|
145
|
+
a Penthera report is ignored) and two levels deep for evidence bundles.
|
|
146
|
+
Symlinks are skipped. A memory chain that does not verify is shown as broken
|
|
147
|
+
and its contents are not used, the same rule scans follow.
|
|
148
|
+
|
|
149
|
+
## Running things from the page
|
|
150
|
+
|
|
151
|
+
Run calls the same functions as the CLI (`executeScan`, `scanDeps`,
|
|
152
|
+
`scanAgents`, `runLoop`) with the same rules. The fix loop needs a clean git
|
|
153
|
+
tree on a branch, works on a local `penthera/fix-<yyyymmdd-hhmm>` branch, runs
|
|
154
|
+
only allow-listed local git commands with hooks off, is always offline with
|
|
155
|
+
egress limited to the URL's host, and never pushes. On top of that:
|
|
156
|
+
|
|
157
|
+
- The project folder must be inside one of the `--project` folders.
|
|
158
|
+
- A URL that is not on this machine (anything but `localhost`, `127.x.x.x`,
|
|
159
|
+
`[::1]` and `*.localhost`) needs its hostname typed back before the run
|
|
160
|
+
starts. Only scan what you own or have written permission to test.
|
|
161
|
+
- One run at a time. Closing the tab does not stop a run; come back to Run and
|
|
162
|
+
it reattaches. Stop finishes the current step, and the fix branch holds only
|
|
163
|
+
verified commits.
|
|
164
|
+
- Reports land in the reports folder (`loop-<timestamp>.json`,
|
|
165
|
+
`deps_<timestamp>.json`, and so on), so every screen picks them up.
|
|
166
|
+
|
|
167
|
+
## Security model
|
|
168
|
+
|
|
169
|
+
The dashboard is a web server on your machine, so any page open in the same
|
|
170
|
+
browser can send it requests. Every request passes, in this order:
|
|
171
|
+
|
|
172
|
+
1. **Host check.** The `Host` header must be exactly `127.0.0.1:<port>` or
|
|
173
|
+
`localhost:<port>`. This blocks DNS rebinding, where `attacker.example`
|
|
174
|
+
re-resolves to 127.0.0.1 so the attacker's page can read the response. It
|
|
175
|
+
runs before the token check, so a rebinding page cannot even redeem the
|
|
176
|
+
link.
|
|
177
|
+
2. **Path check.** No dot segments, encoded dots or slashes, backslashes or NUL
|
|
178
|
+
bytes. Static files come from an allowlist built at startup; no part of a
|
|
179
|
+
request path is ever joined onto a filesystem path.
|
|
180
|
+
3. **Session.** The one-time URL token is exchanged for an `HttpOnly;
|
|
181
|
+
SameSite=Strict` cookie and a redirect to `/`, so the token leaves the
|
|
182
|
+
address bar. Every request, static files included, needs the cookie.
|
|
183
|
+
Requests without it are rate-limited (429 with `Retry-After`).
|
|
184
|
+
4. **Origin.** Every `POST` needs an `Origin` equal to the server's own (and
|
|
185
|
+
`Sec-Fetch-Site: same-origin` when the browser sends it) and a JSON body, so
|
|
186
|
+
a cross-site form or `fetch` cannot change anything.
|
|
187
|
+
|
|
188
|
+
Every response carries:
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self';
|
|
192
|
+
font-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'none'; form-action 'self';
|
|
193
|
+
frame-ancestors 'none'; require-trusted-types-for 'script'
|
|
194
|
+
X-Frame-Options: DENY X-Content-Type-Options: nosniff
|
|
195
|
+
Referrer-Policy: no-referrer Cache-Control: no-store
|
|
196
|
+
Cross-Origin-Opener-Policy / -Resource-Policy / -Embedder-Policy
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
There are no CORS headers, and `OPTIONS` gets a 405. The page has no inline
|
|
200
|
+
script or style, loads nothing from another host (no CDN, fonts, analytics or
|
|
201
|
+
chart library), and never turns data into HTML: finding titles and evidence
|
|
202
|
+
come from the sites and repos you scanned, so they are only ever set as text.
|
|
203
|
+
Report downloads are served as `text/markdown` attachments from the same
|
|
204
|
+
checks; the audience is one of `auditor`, `owner` or `developer`, nothing else.
|
|
205
|
+
|
|
206
|
+
Penthera scans its own dashboard clean with `--profile standard`, signed in and
|
|
207
|
+
not; `tests/ui.test.js` runs that scan on every test run, alongside tests for
|
|
208
|
+
the Host check, the token and cookie, Origin, the headers, the rate limit and
|
|
209
|
+
path traversal.
|
|
210
|
+
|
|
211
|
+
## Design
|
|
212
|
+
|
|
213
|
+
A 1-bit desktop with a terminal inside. The window chrome comes from the Mac
|
|
214
|
+
of the early 90s, and the layout from a planning board the maintainer keeps in
|
|
215
|
+
the same style (every section a pinstriped window with its date on the right,
|
|
216
|
+
bold-ruled columns, a Gantt with dashed milestones): a menu bar, pinstriped title bars with close and zoom boxes,
|
|
217
|
+
a dithered desktop, rounded push buttons where the default one wears a thick
|
|
218
|
+
ring, and alert dialogs with a double frame. The voice, the `▸` progress
|
|
219
|
+
lines, the numbered "What next?" and the `#0000ed` block-letter wordmark come
|
|
220
|
+
straight from the CLI and its demo GIF, so the terminal, the README and the
|
|
221
|
+
dashboard read as one product.
|
|
222
|
+
|
|
223
|
+
- **Black, white and patterns do the work.** Severity is a word plus a
|
|
224
|
+
pattern swatch (solid, hatched, half-tone, dotted, empty), and bars are drawn
|
|
225
|
+
with shade characters `█ ▓ ▒ ░ ·`. Charts fill with hatching and dithering,
|
|
226
|
+
not colour.
|
|
227
|
+
- **One accent.** `#0000ed` marks the active screen, the default button,
|
|
228
|
+
selection, links and chart lines. On black it measures 2.2:1, so there it is
|
|
229
|
+
only a fill (white text on it, 9.5:1), a frame or a glow; text in that hue
|
|
230
|
+
uses the tint `#7a7aff` (6.1:1). On white, `#0000ed` is text-safe (9.3:1).
|
|
231
|
+
- **Green** is kept for the cursor, the prompt and "OK".
|
|
232
|
+
- **Calm where it counts.** Pinstripes only on real windows and dialogs; data
|
|
233
|
+
sits in hairline group boxes, one stat strip, and tables with figure captions
|
|
234
|
+
that say where each number came from.
|
|
235
|
+
- **Both themes pass WCAG AA** for every text node on every screen (measured in
|
|
236
|
+
the browser, composited). Light text uses a 0.6 ink step where the dark
|
|
237
|
+
theme uses 0.5, because 0.5 measures 3.6:1 on paper.
|
|
238
|
+
- **Motion.** The output types itself out and the cursor blinks. With
|
|
239
|
+
`prefers-reduced-motion`, both stop and output appears whole. Screens switch
|
|
240
|
+
with `1`-`8` and have no transition.
|
|
241
|
+
- **Keyboard.** `1`-`8` screens, `/` filter findings, `j`/`k` move through
|
|
242
|
+
findings, `y`/`n`/`q` answer a diff. Every control is a real button or link;
|
|
243
|
+
the approval dialog takes focus when a diff arrives; screen readers get each
|
|
244
|
+
log line whole, never letter by letter.
|