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.
Files changed (114) hide show
  1. package/CHANGELOG.md +227 -0
  2. package/README.md +148 -575
  3. package/bin/scan.js +19 -0
  4. package/docs/commands/README.md +23 -0
  5. package/docs/commands/action.md +21 -0
  6. package/docs/commands/agents.md +38 -0
  7. package/docs/commands/deps.md +115 -0
  8. package/docs/commands/fix.md +53 -0
  9. package/docs/commands/hook.md +69 -0
  10. package/docs/commands/install.md +53 -0
  11. package/docs/commands/scan.md +100 -0
  12. package/docs/commands/skill.md +58 -0
  13. package/docs/compare/README.md +25 -0
  14. package/docs/compare/github.md +60 -0
  15. package/docs/compare/semgrep.md +54 -0
  16. package/docs/compare/snyk.md +62 -0
  17. package/docs/compare/socket.md +78 -0
  18. package/docs/compare/zap.md +59 -0
  19. package/docs/compliance-cra.md +141 -0
  20. package/docs/compliance-nis2.md +3 -1
  21. package/docs/dashboard.md +244 -0
  22. package/docs/evidence.md +8 -4
  23. package/docs/examples/github-actions-deps.yml +4 -4
  24. package/docs/examples/github-actions-scan.yml +4 -4
  25. package/docs/index.md +11 -2
  26. package/docs/internal-audit.md +83 -0
  27. package/docs/marketing.md +151 -0
  28. package/docs/plan.md +101 -0
  29. package/docs/privacy.md +38 -0
  30. package/docs/references.bib +10 -0
  31. package/docs/references.md +1 -0
  32. package/docs/research/socket-positioning-notes.md +183 -0
  33. package/docs/use-cases/README.md +14 -0
  34. package/docs/use-cases/agencies.md +71 -0
  35. package/docs/use-cases/ai-coding-teams.md +81 -0
  36. package/docs/use-cases/eu-sme-compliance.md +68 -0
  37. package/docs/use-cases/open-source-maintainers.md +75 -0
  38. package/docs/use-cases/solo-founder.md +65 -0
  39. package/lib/blackbox/email-dns.js +5 -0
  40. package/lib/compliance/cra.js +525 -0
  41. package/lib/compliance/questionnaire.js +4 -2
  42. package/lib/deps/capabilities.js +49 -12
  43. package/lib/deps/index.js +314 -30
  44. package/lib/deps/license.js +329 -0
  45. package/lib/deps/lockfile.js +29 -3
  46. package/lib/deps/popular-pypi.json +1 -0
  47. package/lib/deps/python/capabilities.js +447 -0
  48. package/lib/deps/python/index.js +234 -0
  49. package/lib/deps/python/lockfiles.js +359 -0
  50. package/lib/deps/python/source.js +396 -0
  51. package/lib/deps/python/toml.js +219 -0
  52. package/lib/deps/report.js +54 -6
  53. package/lib/deps/source.js +149 -24
  54. package/lib/deps/spdx.json +1 -0
  55. package/lib/deps/typosquat.js +24 -13
  56. package/lib/fix/apply.js +83 -19
  57. package/lib/hook/index.js +345 -0
  58. package/lib/hook/policy.js +62 -0
  59. package/lib/install/index.js +59 -18
  60. package/lib/install/policy.js +27 -7
  61. package/lib/jurisdictions/nl.json +9 -0
  62. package/lib/memory/repo-suppress.js +11 -3
  63. package/lib/references.json +77 -0
  64. package/lib/remediation/index.js +9 -0
  65. package/lib/retirejs.js +69 -17
  66. package/lib/rules/regex-guard.js +368 -0
  67. package/lib/templates.js +13 -6
  68. package/lib/tls.js +7 -0
  69. package/lib/whitebox/aibom.js +384 -0
  70. package/lib/whitebox/frameworks.js +8 -5
  71. package/lib/whitebox/sbom.js +45 -10
  72. package/lib/whitebox/secrets.js +31 -8
  73. package/package.json +8 -3
  74. package/skills/penthera/SKILL.md +55 -8
  75. package/src/cli/deps.js +81 -6
  76. package/src/cli/evidence.js +14 -4
  77. package/src/cli/hook.js +131 -0
  78. package/src/cli/install.js +14 -5
  79. package/src/cli/report-outputs.js +25 -2
  80. package/src/cli/ui.js +89 -0
  81. package/src/cli.js +81 -11
  82. package/src/report/audience.js +10 -10
  83. package/src/report/evidence.js +33 -14
  84. package/src/report/footer.js +11 -0
  85. package/src/report/markdown.js +6 -3
  86. package/src/report/md-escape.js +16 -0
  87. package/src/reporter.js +1 -0
  88. package/src/scan-url.js +5 -1
  89. package/src/ui/api/data.js +309 -0
  90. package/src/ui/api/demo.js +464 -0
  91. package/src/ui/api/routes.js +134 -0
  92. package/src/ui/api/runs.js +243 -0
  93. package/src/ui/api/summarize.js +451 -0
  94. package/src/ui/security.js +153 -0
  95. package/src/ui/server.js +186 -0
  96. package/src/ui/static/app.css +723 -0
  97. package/src/ui/static/favicon.svg +1 -0
  98. package/src/ui/static/index.html +57 -0
  99. package/src/ui/static/js/api.js +29 -0
  100. package/src/ui/static/js/app.js +138 -0
  101. package/src/ui/static/js/charts.js +207 -0
  102. package/src/ui/static/js/copy.js +79 -0
  103. package/src/ui/static/js/dom.js +120 -0
  104. package/src/ui/static/js/format.js +42 -0
  105. package/src/ui/static/js/theme.js +10 -0
  106. package/src/ui/static/js/typer.js +99 -0
  107. package/src/ui/static/js/views/ai.js +68 -0
  108. package/src/ui/static/js/views/deps.js +96 -0
  109. package/src/ui/static/js/views/evidence.js +115 -0
  110. package/src/ui/static/js/views/findings.js +165 -0
  111. package/src/ui/static/js/views/history.js +92 -0
  112. package/src/ui/static/js/views/overview.js +184 -0
  113. package/src/ui/static/js/views/run.js +349 -0
  114. package/src/ui/static/js/views/settings.js +67 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,217 @@ All notable changes to Penthera are documented here. Versioning follows [SemVer]
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.6.0] - 2026-10-19
8
+
9
+ Hardening and reach. An independent 360 review found three high-severity bugs, two of them reproduced; all are fixed with regression tests, and the open code-scanning alerts went from 18 to the 2 that need a second maintainer. `penthera deps` now covers Python, `penthera ui` adds a local dashboard (black or white, in the project blue), and every release passes an internal audit first. 1.5.0 was never published to npm; this release includes it.
10
+
11
+ ### Security
12
+
13
+ - Cleared the open code-scanning alerts. The community-template regex guard
14
+ was itself a polynomial regex; it is now a linear scan, and an invalid
15
+ extractor regex no longer aborts a template. Markdown table cells escape
16
+ backslashes first (one shared helper). `<script>` extraction is a tokenizer
17
+ that accepts any case and junk in closing tags. Release workflow: read-only
18
+ top-level token, hash-verified npm, no dependency cache. Docker base image
19
+ pinned by digest. fast-check property tests fuzz the untrusted-input parsers.
20
+
21
+ Fixes from an independent 360 review of `main`. The first three were
22
+ reproduced; each fix has a regression test that fails without it.
23
+
24
+ - **High: tar desync hid install scripts from the install firewall and
25
+ `penthera deps`.** A GNU base-256 size field parsed as 0, the reader lost its
26
+ place, and 512 zero bytes then read as end-of-archive, so `package.json` and
27
+ everything after it went unscanned and the package looked clean. The tar
28
+ reader now handles base-256 sizes and pax `size=`, checks every header
29
+ checksum and fails closed on any anomaly (malformed size, truncation, data
30
+ after the end marker). A package whose archive or `package.json` cannot be
31
+ read is reported as "could not be scanned" (high) and always needs approval
32
+ in `penthera install`; a lockfile `hasInstallScript` that the scan cannot
33
+ find is a high finding and is always denied (except the known benign case
34
+ of a package that ships only prebuilt `.node` binaries, like fsevents 2.x)
35
+ - **High: `applyDiff` wrote through a dangling symlink out of the repo.** Every
36
+ path component is now `lstat`-ed and any symlink is refused; creates use
37
+ `O_CREAT|O_EXCL|O_NOFOLLOW`
38
+ - **High: `.GIT/` bypassed the `.git` guard on case-insensitive file systems.**
39
+ Any path segment that is `.git` in any case, at any depth (plus HFS+ and
40
+ NTFS aliases such as `.git.` and `GIT~1`), is refused, and fix diffs may no
41
+ longer touch `.gitmodules`
42
+ - PR comments escape HTML, Markdown links and images, `@` mentions, `#` refs
43
+ and bare URLs in package names, versions, paths and snippets from the
44
+ lockfile, keep code spans on one line, and cap each field at 200 characters
45
+ - `penthera evidence verify` no longer passes a signed bundle whose signer was
46
+ not checked: a signature only verifies against `--allowed-signers`, and a
47
+ manifest that declares a signature with no `.sig` fails. Unsigned bundles
48
+ pass with an UNSIGNED warning; new `--require-signature` fails them
49
+ - `penthera install` refuses git, hosted-git and tarball-URL specs, and lockfile
50
+ entries resolved outside the configured registries, unless
51
+ `--allow-non-registry` is passed. `npm cache add` runs with `--ignore-scripts`
52
+ - `penthera install` applies with `npm ci`, so npm installs exactly the
53
+ reviewed lockfile and cannot re-resolve before scripts run
54
+ - `penthera deps` now honours `--audience`, `--report-template`, `--evidence`
55
+ (with `--sign-key`) and `--baseline`, and rejects scan-only flags such as
56
+ `--memory` with a clear error instead of ignoring them
57
+ - Gzip and tar size limits are enforced while unpacking (`maxOutputLength` on
58
+ gunzip, per-file and total caps in the tar reader)
59
+ - The pre-commit hook reads `penthera.policy.json` and `penthera.suppress.json`
60
+ from the git index, warns when an unstaged copy is being ignored, and never
61
+ follows a staged symlink in agent config out of the repo
62
+ - `--base` refs are validated (no leading `-`, a plain ref charset) and passed
63
+ after `--end-of-options`, in `penthera deps` and in the GitHub Action's fetch
64
+ - `git status` and friends on a scanned repo (fix apply, evidence bundle git
65
+ info, `--base` reads) run with `core.fsmonitor=false`, no hooks and no
66
+ transports
67
+ - The Action only edits marker comments posted by `github-actions[bot]`
68
+ - `--offline` no longer makes DNS TXT/MX lookups for SPF/DMARC
69
+ - Report citations now cover `dependency-risk`, `license`, `agent-config` and
70
+ the machine-audit categories; `license` findings get their own remediation
71
+ - Docs: `docs/plan.md` lists only what v1.5.0 shipped; top-level `--help`
72
+ lists `penthera hook`
73
+
74
+ ### Added
75
+
76
+ - **Internal testing audit** (`npm run audit:internal`), the release gate:
77
+ tests, benchmark drift, a self-scan against `audit/baseline.json`, a CLI
78
+ smoke matrix, package contents and size, zero third-party egress offline,
79
+ supply chain and version/docs checks, written to `audit/REPORT.md`. Runs
80
+ weekly in CI. See [docs/internal-audit.md](docs/internal-audit.md)
81
+ - **Marketing automation that drafts, never posts** (`docs/marketing.md`): no
82
+ social-media tokens, no tracking, no auto-posting; every workflow SHA-pinned
83
+ with least-privilege permissions and a `workflow_dispatch` dry run
84
+ - Release post drafts: `publish.yml` writes a LinkedIn (~600 characters) and
85
+ an X/Bluesky (≤280) post from the CHANGELOG section to the job summary and
86
+ a collapsed "Share this release" section in the GitHub Release
87
+ (`scripts/marketing/release-post.mjs`)
88
+ - Incident radar (`incident-radar.yml`, daily): new npm and PyPI malware
89
+ advisories from the public GitHub Advisory Database become
90
+ `incident-radar` issues with affected versions, an IOC checklist and a
91
+ draft "check if you're affected" post. Popular packages get their own
92
+ issue (at most 5 per run); the rest are batched into one issue
93
+ - Demo media (`demo-media.yml`): VHS tapes in `assets/tapes/` for a URL
94
+ scan, `penthera agents` and `penthera deps --diff`, re-rendered on release
95
+ and opened as a PR
96
+ - Monthly stats issue (`monthly-stats.yml`): npm downloads, stars, forks,
97
+ skills.sh installs, dependents and merged PRs, with month-over-month
98
+ changes and a draft post
99
+ - Contributor flywheel (`contributor-flywheel.yml`): when fewer than 3
100
+ `good first issue` issues are open, one reminder lists the
101
+ `TODO(good-first-issue)` markers in the code
102
+ - **Report footer**: Markdown reports, audience reports, the PR comment and
103
+ the evidence bundle end with one line, "Checked by Penthera, open-source
104
+ security for the apps and AI systems you ship". Never in SARIF or JSON.
105
+ `--no-footer` (or `footer: "false"` in the Action) leaves it off. Evidence
106
+ bundles now include a `README.md`
107
+ - **Python support for `penthera deps`** (`lib/deps/python/`): reads `uv.lock`,
108
+ `poetry.lock`, `pdm.lock`, `Pipfile.lock` and `requirements*.txt` (pinned and
109
+ `--hash` lines, `-r` includes, pip-compile `# via` for direct deps), and the
110
+ installed `.venv` / `venv` / `--venv <path>` through `dist-info` `METADATA`
111
+ and `RECORD`, with no pip or interpreter. A Python tokenizer blanks comments
112
+ and docstrings; patterns cover shell, network, env bulk access and
113
+ exfiltration, eval/exec/compile, computed imports, unpickling, native
114
+ extensions, obfuscation (`exec` of base64/zlib payloads, encoded blobs,
115
+ PyArmor) and the same AI-agent indicators as npm. Install-time and
116
+ persistence code: `setup.py` custom commands, `.pth` import lines (scored by
117
+ what the imported module can do), `.pth` files no distribution owns, code that
118
+ writes `.pth` files, and installed files that no longer match `RECORD`. Same
119
+ capability ids, findings, diff, PR comment and SARIF as npm; projects with
120
+ both get one combined report
121
+ - `--diff` / `--base` for Python lockfiles. Old versions come from pip's HTTP
122
+ cache (sha256 from the lockfile) or uv's cache (recorded hash), else they are
123
+ marked "not compared"
124
+ - PyPI typosquat check against a vendored list of the top 8,000 PyPI projects
125
+ (`lib/deps/popular-pypi.json`, PEP 503 normalised, refreshed at release time by
126
+ `scripts/refresh-popular-pypi.mjs`), including `python-` / `-py` affixes
127
+
128
+ ### Changed
129
+
130
+ - The live test suites (`pentest-live`, `-recon`, `-adaptive`) are opt-in:
131
+ they run only with `PENTEST_BASE_URL` or a `pentest.config.js`, instead of
132
+ probing whatever listens on `localhost:3000` during `npm test`.
133
+
134
+ ### Fixed
135
+
136
+ - Repo scans skip nested git repositories and worktrees (any subfolder with
137
+ its own `.git`, such as coding-agent worktrees under `.claude/worktrees`),
138
+ instead of reporting their files as this repo's, and no longer follow
139
+ symlinked folders out of the repo.
140
+ - The secret scanner no longer reports a value that is only a template
141
+ placeholder (`apiKey: "${key}"`, `{{ api_key }}`) as a hardcoded secret.
142
+ - `penthera-scan --help` and `--version` exit 0 instead of starting the wizard.
143
+ - The example workflows in `docs/examples/` pin actions by commit SHA.
144
+
145
+ ### Docs
146
+
147
+ - README cut from about 45 KB to under 20 KB. It opens with a three-command
148
+ "Try it in 60 seconds" block, a "Who it is for" table, and a "By the
149
+ numbers" block (benchmark, rule and test counts, references, release
150
+ provenance). Per-command detail moved to `docs/commands/` and network use to
151
+ `docs/privacy.md`.
152
+ - Use-case pages in `docs/use-cases/`: before launch, teams adopting coding
153
+ agents, open-source maintainers, EU SMEs with NIS2 or CRA duties, agencies.
154
+ - Comparison pages in `docs/compare/` for Socket, Snyk, GitHub Dependabot and
155
+ code scanning, OWASP ZAP and Semgrep, framed as using the tools together, with
156
+ sources and a last-checked date.
157
+ - `docs/research/socket-positioning-notes.md`: how Socket presents itself and
158
+ what Penthera's docs took from it.
159
+ - `npm run docs:numbers` prints the counts quoted in the README.
160
+
161
+ ## [1.5.0] - 2026-10-19
162
+
163
+ Blocks problems at commit time, adds license policy, and extends the EU
164
+ evidence to the Cyber Resilience Act. The GitHub Action is now ready for the
165
+ Marketplace as "Penthera Security Review". Penthera also has a clearer
166
+ problem statement: open-source security for the apps and AI systems you ship.
167
+
168
+ ### Docs
169
+
170
+ - Problem statement: "open-source security for the apps and AI systems you
171
+ ship", organised around three moments (before you deploy, what you build
172
+ with, after you ship). README, package, plugin, skill and repository
173
+ descriptions updated. Roadmap gains v1.6.0 "Before you deploy" (preview
174
+ deployment scanning, `penthera ship`) and v1.7.0 "After you ship"
175
+ (`penthera watch`). New `docs/plan.md` sets measurable quality gates to v2.0.
176
+
177
+ ### Added
178
+
179
+ - **`penthera hook install|uninstall|run`**: a pre-commit hook that checks
180
+ staged content only (the git index): secrets and AI provider keys, the
181
+ `penthera agents` rules on staged `.mcp.json`, `CLAUDE.md`, `AGENTS.md`,
182
+ `.cursor/`, `.claude/` and `skills/`, and, when `package-lock.json` is staged,
183
+ the capability diff against HEAD plus the license policy for the packages the
184
+ commit adds. Blocks on high and critical by default; one line per finding with
185
+ a fix hint and a `penthera.suppress.json` id. An existing hook is kept as
186
+ `pre-commit.pre-penthera`, runs first, and is restored by `uninstall`. Refuses
187
+ to write into a `core.hooksPath` managed by husky or lefthook without `--force`.
188
+ `.pre-commit-hooks.yaml` for pre-commit.com. Configured by a new `hook`
189
+ section in `penthera.policy.json` (`blockOn`, `checks`, `ignore`)
190
+ - **License policy**: `penthera deps --license-policy <preset|file>` and a
191
+ `licenses` section in `penthera.policy.json` (`preset`, `allow`, `deny`,
192
+ `allowPackages`, `unknown`). Presets `permissive`, `weak-copyleft-ok` and
193
+ `no-agpl`. A small SPDX expression parser handles `AND`/`OR`/`WITH`,
194
+ parentheses, `+` and `LicenseRef-`, and matches deprecated ids (`GPL-3.0`) to
195
+ their current form. Breaches and `UNLICENSED` are high; missing, custom and
196
+ non-SPDX licenses are medium. Findings use category `license`; the SPDX id
197
+ list is vendored (`lib/deps/spdx.json`). CycloneDX SBOM components now carry
198
+ their license
199
+ - **CRA Article 14 reporting helper** (`penthera --cra-init cra.json`,
200
+ `penthera --cra cra.json`, `lib/compliance/cra.js`): for an actively exploited
201
+ vulnerability (24h early warning, 72h notification, final report 14 days after
202
+ a fix is available) or a severe incident (24h, 72h, final report one month
203
+ after the notification). Computes due dates in UTC and local time (hours
204
+ elapsed, days and months on the calendar, DST-safe), flags overdue and late
205
+ reports, drafts each report against Art. 14(2)/(4) with `NEEDS INPUT` for
206
+ missing facts, adds an Art. 14(8) user advisory, and can prefill the affected
207
+ component, purl and CVEs from a Penthera SBOM and scan JSON. NL profile names
208
+ NCSC-NL and the ENISA Single Reporting Platform. Drafts, not the official
209
+ form, not legal advice. Guide: `docs/compliance-cra.md`
210
+ - **CycloneDX 1.6 AI-BOM** (`penthera --repo . --aibom aibom.cdx.json`,
211
+ `lib/whitebox/aibom.js`): AI SDK dependencies, model identifiers in code as
212
+ `machine-learning-model` components with `modelCard` and file:line evidence,
213
+ MCP servers as `services`, and Agent Skills and prompt files as hashed `data`
214
+ components. Offline. Tests validate the output against the official
215
+ CycloneDX 1.6 schema, vendored in `tests/fixtures/cyclonedx/` (new dev
216
+ dependency: `ajv`)
217
+
7
218
  ## [1.4.0] - 2026-10-19
8
219
 
9
220
  The biggest release so far, covering the v1.3.0 "AI toolchain" and v1.4.0
@@ -22,6 +233,22 @@ Requires Node 22+. Upgrading from 1.1.x or 1.2.x needs no config changes.
22
233
 
23
234
  ### Added
24
235
 
236
+ - **`penthera ui [--open] [--port 0] [--project <dir>] [--reports <dir>] [--demo]`**:
237
+ a local dashboard on 127.0.0.1 (random port, one-time URL), styled as a
238
+ 1-bit early-90s Mac desktop with a terminal inside, in dark and light themes.
239
+ Overview (posture per project, severity mix, findings over time, time to
240
+ fix, hosts contacted; a three-step start when there is no data yet),
241
+ Findings (filters, a plain-words explanation, evidence, sources, fix diff),
242
+ Run (scan, check dependencies, audit AI tooling, or the fix loop with an
243
+ Apply / Skip / Stop dialog on every diff, live output over SSE), History
244
+ (new, fixed and still open between two scans), Dependencies, AI tooling,
245
+ Evidence (create a bundle from the latest scan, verify in one click,
246
+ download the auditor report) and Settings. Reads only the chosen folders and
247
+ `~/.penthera`; no network, no new dependencies, no build step. Host check
248
+ against DNS rebinding, one-time token swapped for an HttpOnly SameSite=Strict
249
+ cookie, Origin check and JSON-only bodies on state changes, strict CSP, no
250
+ CORS, rate-limited unauthenticated requests, allowlisted static files.
251
+ Penthera scans it clean. `--demo` seeds fake data. See `docs/dashboard.md`
25
252
  - **GitHub Action** (`uses: danoszz/penthera@<sha>`, `action.yml`): on PRs that
26
253
  change the lockfile it runs `penthera deps --base <PR base>`, upserts one PR
27
254
  comment marked `<!-- penthera-deps -->` (edited in place on every push), and