penthera 1.2.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +269 -0
- package/README.md +493 -45
- package/docs/METHODOLOGY.md +321 -0
- package/docs/compliance-cra.md +141 -0
- package/docs/compliance-nis2.md +3 -1
- package/docs/evidence.md +158 -0
- package/docs/examples/github-actions-deps.yml +105 -0
- package/docs/examples/github-actions-scan.yml +1 -1
- package/docs/examples/pr-dependency-review.yml +56 -0
- package/docs/funding/due-diligence-checklist.md +79 -0
- package/docs/funding/nlnet-ngi-zero-draft.md +273 -0
- package/docs/funding/partner-one-pager.md +84 -0
- package/docs/funding/sponsor-tiers.md +81 -0
- package/docs/index.md +12 -1
- package/docs/local-loop.md +276 -0
- package/docs/plan.md +100 -0
- package/docs/references.bib +539 -0
- package/docs/references.md +77 -0
- package/docs/release-plan.md +228 -0
- package/lib/adaptive-probes.js +8 -5
- package/lib/agents/discover.js +384 -0
- package/lib/agents/hidden-content.js +387 -0
- package/lib/agents/index.js +286 -0
- package/lib/agents/lock.js +115 -0
- package/lib/agents/owasp.js +83 -0
- package/lib/agents/rules.js +376 -0
- package/lib/compliance/cra.js +525 -0
- package/lib/crawler.js +5 -15
- package/lib/data/retire-jsrepository.json.gz +0 -0
- package/lib/data/retire-jsrepository.meta.json +7 -0
- package/lib/deps/capabilities.js +523 -0
- package/lib/deps/diff.js +84 -0
- package/lib/deps/index.js +440 -0
- package/lib/deps/license.js +329 -0
- package/lib/deps/lockfile.js +109 -0
- package/lib/deps/online.js +132 -0
- package/lib/deps/popular-packages.json +1 -0
- package/lib/deps/report.js +190 -0
- package/lib/deps/source.js +171 -0
- package/lib/deps/spdx.json +1 -0
- package/lib/deps/typosquat.js +113 -0
- package/lib/fix/apply.js +95 -0
- package/lib/fix/diff.js +199 -0
- package/lib/fix/index.js +129 -0
- package/lib/fix/model.js +108 -0
- package/lib/fix/recipes/cookies.js +130 -0
- package/lib/fix/recipes/cors.js +116 -0
- package/lib/fix/recipes/headers.js +250 -0
- package/lib/fix/recipes/rate-limit.js +211 -0
- package/lib/fix/recipes/secrets.js +110 -0
- package/lib/fix/util.js +231 -0
- package/lib/fuzzer.js +14 -8
- package/lib/hook/index.js +312 -0
- package/lib/hook/policy.js +62 -0
- package/lib/injections.js +19 -15
- package/lib/install/index.js +271 -0
- package/lib/install/policy.js +125 -0
- package/lib/jurisdictions/nl.json +9 -0
- package/lib/memory/history.js +52 -0
- package/lib/memory/index.js +111 -0
- package/lib/memory/repo-suppress.js +64 -0
- package/lib/memory/store.js +325 -0
- package/lib/memory/views.js +198 -0
- package/lib/params.js +4 -12
- package/lib/provenance.js +2 -0
- package/lib/recon.js +12 -20
- package/lib/references.js +31 -0
- package/lib/references.json +374 -0
- package/lib/remediation/index.js +28 -0
- package/lib/retirejs.js +50 -22
- package/lib/templates.js +7 -10
- package/lib/whitebox/aibom.js +384 -0
- package/lib/whitebox/frameworks.js +1 -1
- package/lib/whitebox/sbom.js +45 -10
- package/lib/whitebox/secrets.js +11 -1
- package/package.json +17 -4
- package/skills/penthera/SKILL.md +132 -22
- package/src/agent/git.js +87 -0
- package/src/agent/loop.js +519 -0
- package/src/agent/tests.js +48 -0
- package/src/cli/agent.js +183 -0
- package/src/cli/deps.js +104 -0
- package/src/cli/evidence.js +67 -0
- package/src/cli/fix.js +191 -0
- package/src/cli/hook.js +131 -0
- package/src/cli/install.js +225 -0
- package/src/cli/memory.js +146 -0
- package/src/cli/merge-results.js +2 -0
- package/src/cli/report-outputs.js +72 -0
- package/src/cli/run-scan.js +2 -0
- package/src/cli.js +212 -8
- package/src/report/audience.js +270 -0
- package/src/report/evidence.js +253 -0
- package/src/report/markdown.js +65 -2
- package/src/report/model.js +212 -0
- package/src/report/template.js +175 -0
- package/src/report/timeline.js +145 -0
- package/src/reporter.js +109 -5
- package/src/scan-url.js +31 -7
- package/src/utils/http.js +252 -11
- package/src/utils/url.js +23 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,275 @@ All notable changes to Penthera are documented here. Versioning follows [SemVer]
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.5.0] - 2026-10-19
|
|
8
|
+
|
|
9
|
+
Blocks problems at commit time, adds license policy, and extends the EU
|
|
10
|
+
evidence to the Cyber Resilience Act. The GitHub Action is now ready for the
|
|
11
|
+
Marketplace as "Penthera Security Review". Penthera also has a clearer
|
|
12
|
+
problem statement: open-source security for the apps and AI systems you ship.
|
|
13
|
+
|
|
14
|
+
### Docs
|
|
15
|
+
|
|
16
|
+
- Problem statement: "open-source security for the apps and AI systems you
|
|
17
|
+
ship", organised around three moments (before you deploy, what you build
|
|
18
|
+
with, after you ship). README, package, plugin, skill and repository
|
|
19
|
+
descriptions updated. Roadmap gains v1.6.0 "Before you deploy" (preview
|
|
20
|
+
deployment scanning, `penthera ship`) and v1.7.0 "After you ship"
|
|
21
|
+
(`penthera watch`). New `docs/plan.md` sets measurable quality gates to v2.0.
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- **`penthera hook install|uninstall|run`**: a pre-commit hook that checks
|
|
26
|
+
staged content only (the git index): secrets and AI provider keys, the
|
|
27
|
+
`penthera agents` rules on staged `.mcp.json`, `CLAUDE.md`, `AGENTS.md`,
|
|
28
|
+
`.cursor/`, `.claude/` and `skills/`, and, when `package-lock.json` is staged,
|
|
29
|
+
the capability diff against HEAD plus the license policy for the packages the
|
|
30
|
+
commit adds. Blocks on high and critical by default; one line per finding with
|
|
31
|
+
a fix hint and a `penthera.suppress.json` id. An existing hook is kept as
|
|
32
|
+
`pre-commit.pre-penthera`, runs first, and is restored by `uninstall`. Refuses
|
|
33
|
+
to write into a `core.hooksPath` managed by husky or lefthook without `--force`.
|
|
34
|
+
`.pre-commit-hooks.yaml` for pre-commit.com. Configured by a new `hook`
|
|
35
|
+
section in `penthera.policy.json` (`blockOn`, `checks`, `ignore`)
|
|
36
|
+
- **License policy**: `penthera deps --license-policy <preset|file>` and a
|
|
37
|
+
`licenses` section in `penthera.policy.json` (`preset`, `allow`, `deny`,
|
|
38
|
+
`allowPackages`, `unknown`). Presets `permissive`, `weak-copyleft-ok` and
|
|
39
|
+
`no-agpl`. A small SPDX expression parser handles `AND`/`OR`/`WITH`,
|
|
40
|
+
parentheses, `+` and `LicenseRef-`, and matches deprecated ids (`GPL-3.0`) to
|
|
41
|
+
their current form. Breaches and `UNLICENSED` are high; missing, custom and
|
|
42
|
+
non-SPDX licenses are medium. Findings use category `license`; the SPDX id
|
|
43
|
+
list is vendored (`lib/deps/spdx.json`). CycloneDX SBOM components now carry
|
|
44
|
+
their license
|
|
45
|
+
- **CRA Article 14 reporting helper** (`penthera --cra-init cra.json`,
|
|
46
|
+
`penthera --cra cra.json`, `lib/compliance/cra.js`): for an actively exploited
|
|
47
|
+
vulnerability (24h early warning, 72h notification, final report 14 days after
|
|
48
|
+
a fix is available) or a severe incident (24h, 72h, final report one month
|
|
49
|
+
after the notification). Computes due dates in UTC and local time (hours
|
|
50
|
+
elapsed, days and months on the calendar, DST-safe), flags overdue and late
|
|
51
|
+
reports, drafts each report against Art. 14(2)/(4) with `NEEDS INPUT` for
|
|
52
|
+
missing facts, adds an Art. 14(8) user advisory, and can prefill the affected
|
|
53
|
+
component, purl and CVEs from a Penthera SBOM and scan JSON. NL profile names
|
|
54
|
+
NCSC-NL and the ENISA Single Reporting Platform. Drafts, not the official
|
|
55
|
+
form, not legal advice. Guide: `docs/compliance-cra.md`
|
|
56
|
+
- **CycloneDX 1.6 AI-BOM** (`penthera --repo . --aibom aibom.cdx.json`,
|
|
57
|
+
`lib/whitebox/aibom.js`): AI SDK dependencies, model identifiers in code as
|
|
58
|
+
`machine-learning-model` components with `modelCard` and file:line evidence,
|
|
59
|
+
MCP servers as `services`, and Agent Skills and prompt files as hashed `data`
|
|
60
|
+
components. Offline. Tests validate the output against the official
|
|
61
|
+
CycloneDX 1.6 schema, vendored in `tests/fixtures/cyclonedx/` (new dev
|
|
62
|
+
dependency: `ajv`)
|
|
63
|
+
|
|
64
|
+
## [1.4.0] - 2026-10-19
|
|
65
|
+
|
|
66
|
+
The biggest release so far, covering the v1.3.0 "AI toolchain" and v1.4.0
|
|
67
|
+
"Local loop" milestones together. Penthera now does the routine work of a small
|
|
68
|
+
security team on your own machine:
|
|
69
|
+
- tests your app;
|
|
70
|
+
- vets and guards your dependencies;
|
|
71
|
+
- audits your AI tooling;
|
|
72
|
+
- fixes what it finds on a local branch and verifies each fix;
|
|
73
|
+
- writes reports and evidence for auditors.
|
|
74
|
+
|
|
75
|
+
It still runs offline, with no telemetry. The first outside contribution, from
|
|
76
|
+
@Nurana100, is in this release.
|
|
77
|
+
|
|
78
|
+
Requires Node 22+. Upgrading from 1.1.x or 1.2.x needs no config changes.
|
|
79
|
+
|
|
80
|
+
### Added
|
|
81
|
+
|
|
82
|
+
- **GitHub Action** (`uses: danoszz/penthera@<sha>`, `action.yml`): on PRs that
|
|
83
|
+
change the lockfile it runs `penthera deps --base <PR base>`, upserts one PR
|
|
84
|
+
comment marked `<!-- penthera-deps -->` (edited in place on every push), and
|
|
85
|
+
uploads SARIF. Runs from the action's own checkout with no npx or npm install.
|
|
86
|
+
Fork PRs get the diff in the job summary. Also `mode: agents` and `mode: scan`,
|
|
87
|
+
plus `fail-on`. Example: `docs/examples/pr-dependency-review.yml`
|
|
88
|
+
- **`penthera agents [path] [--home] [--pin]`**: an offline, deterministic audit
|
|
89
|
+
of AI developer tooling. It finds and parses `.mcp.json`, `.cursor/`,
|
|
90
|
+
`.claude/`, `.vscode/mcp.json`, `AGENTS.md`, `CLAUDE.md`, `.cursorrules`,
|
|
91
|
+
`.github/copilot-instructions.md` and skill folders; with `--home` also
|
|
92
|
+
`~/.claude` (settings, hooks, permissions, plugins, skills), `~/.claude.json`,
|
|
93
|
+
`~/.cursor/mcp.json` and the Claude Desktop config. Read-only, no network, no
|
|
94
|
+
LLM judge
|
|
95
|
+
- Hidden-content engine (`lib/agents/hidden-content.js`): Unicode tag
|
|
96
|
+
characters (decoded), zero-width and bidi controls, variation-selector
|
|
97
|
+
smuggling, whitespace inflation, instructions in HTML comments, text aimed at
|
|
98
|
+
a scanner, base64 blobs (decoded and classified), binaries and archives in
|
|
99
|
+
skill folders by magic bytes, symlinks that leave a skill, and `curl | sh` /
|
|
100
|
+
`eval` style remote execution
|
|
101
|
+
- Risky-config rules: unpinned `npx -y` / `uvx` / `bunx` / `pnpm dlx` MCP
|
|
102
|
+
servers, inline secrets in server env/headers/args (via `findSecretsInText()`),
|
|
103
|
+
plain-HTTP remote servers, hooks that auto-approve or pipe to a shell,
|
|
104
|
+
`Bash(*)` and other wildcard permissions, `bypassPermissions`, credential-file
|
|
105
|
+
allows, wildcard `allowed-tools`, and unpinned plugin marketplaces
|
|
106
|
+
- `penthera.lock`: `--pin` records SHA-256 hashes of every skill folder, MCP
|
|
107
|
+
server definition, hook and installed plugin; later runs report changed (rug
|
|
108
|
+
pull), new and removed entries
|
|
109
|
+
- A–F grade for the agent setup in the terminal and Markdown reports. Findings
|
|
110
|
+
use category `agent-config`, map to OWASP MCP Top 10 and Agentic (ASI) ids,
|
|
111
|
+
and get per-rule SARIF ids (`agents/<rule>`)
|
|
112
|
+
- Agent Skill: Workflow 6 ("audit my MCP servers / skills / agent config")
|
|
113
|
+
- `docs/METHODOLOGY.md`: threat model, what black-box and white-box scanning
|
|
114
|
+
can and cannot find, the confidence model, false-positive controls, the
|
|
115
|
+
non-destructive default, offline operation, and how new attack techniques
|
|
116
|
+
are adopted (reviewed rules in releases, never fetched at run time). Design
|
|
117
|
+
choices cite published research and standards
|
|
118
|
+
- `docs/references.bib` and `docs/references.md`: 48 references, each checked
|
|
119
|
+
against the publisher or standards body, grouped by topic
|
|
120
|
+
- Per-finding citations: `lib/references.json` maps each finding category to
|
|
121
|
+
1-3 references. The Markdown report adds a "Why this matters / Sources" line
|
|
122
|
+
per finding and a "Sources" line per action-plan item; SARIF rules get
|
|
123
|
+
`helpUri`, `help` and `properties.references`
|
|
124
|
+
- Accuracy benchmark: `npm run bench` scans the mock server, two new local lab
|
|
125
|
+
targets (vulnerable and decoy) and a generated repo fixture, scores precision
|
|
126
|
+
and recall against `bench/ground-truth.json`, and writes `bench/RESULTS.md`.
|
|
127
|
+
Offline and seeded; `npm test` fails if it drops below the CI floor.
|
|
128
|
+
Optional Juice Shop and crAPI targets are documented
|
|
129
|
+
- `CITATION.cff`, so GitHub shows "Cite this repository"
|
|
130
|
+
- **`penthera deps [path]`**: offline, deterministic dependency risk scanning
|
|
131
|
+
for npm. Reads `package-lock.json` (v1-v3), statically scans every installed
|
|
132
|
+
package and reports what it can do, with `file:line` evidence: install
|
|
133
|
+
scripts (including implicit `node-gyp`), shell, network, writes outside its
|
|
134
|
+
folder, environment reads and bulk access, `eval` / `new Function` / `vm`,
|
|
135
|
+
computed `require`/`import`, native binaries, and obfuscation signals
|
|
136
|
+
- **Capability diff** (`--diff <lockfile|dir>`, `--base <git-ref>`): packages
|
|
137
|
+
that are new or that gained capabilities in an upgrade. Old versions come
|
|
138
|
+
from the base tree or npm's local content cache, verified against the
|
|
139
|
+
lockfile integrity, so the diff works offline
|
|
140
|
+
- Attack indicators: writes to `~/.claude`, `~/.cursor`, `.mcp.json` or the
|
|
141
|
+
Claude Desktop config, running the `claude` / `gemini` / `q` CLIs (the
|
|
142
|
+
s1ngularity pattern), GitHub token harvesting, and the whole environment
|
|
143
|
+
serialised next to network code
|
|
144
|
+
- Typosquat / slopsquat check against a vendored list of ~7,800 popular npm
|
|
145
|
+
names (`lib/deps/popular-packages.json`, from npm-high-impact), refreshed at
|
|
146
|
+
release time by `npm run refresh:popular`. Nothing is fetched at runtime
|
|
147
|
+
- `--online` (off by default, the only network use): npm registry metadata for
|
|
148
|
+
fresh versions, brand-new packages, publisher changes and deprecations
|
|
149
|
+
- `--pr-comment <file>` and an example workflow
|
|
150
|
+
([`docs/examples/github-actions-deps.yml`](docs/examples/github-actions-deps.yml))
|
|
151
|
+
that comments the capability diff on PRs that change the lockfile
|
|
152
|
+
- Findings use category `dependency-risk` and source `deps-scan`; SARIF
|
|
153
|
+
results now carry a start line when a finding has one
|
|
154
|
+
- **`penthera install [pkg...]`**: an install firewall on the `deps` engine.
|
|
155
|
+
npm resolves the new tree in a temporary copy with scripts off
|
|
156
|
+
(`--package-lock-only --ignore-scripts`), new tarballs are fetched with
|
|
157
|
+
`npm cache add` and read back only after an integrity check, and the
|
|
158
|
+
capability diff, new install scripts (with their commands) and typosquats
|
|
159
|
+
are shown before anything in the project changes. `penthera.policy.json`
|
|
160
|
+
(`allow` names/globs, `deny` and `requireApproval` capabilities) decides;
|
|
161
|
+
by default new install scripts, AI-config writes, AI CLI invocation, token
|
|
162
|
+
harvesting, obfuscation, typosquats and unreadable packages need approval.
|
|
163
|
+
Interactive by default, `--yes` for CI (installs only when nothing breaches
|
|
164
|
+
the policy), `--dry-run` to report. On approval the reviewed lockfile is
|
|
165
|
+
installed as is, with `--ignore-scripts` unless the scripts were approved
|
|
166
|
+
(on npm 12+, approved scripts are pinned in `package.json` `allowScripts`).
|
|
167
|
+
An abort leaves the project byte for byte unchanged. npm's registry traffic
|
|
168
|
+
is the only egress, and it is printed
|
|
169
|
+
- `scanDeps()` accepts `treeRoot` and a list of cache dirs; the diff output
|
|
170
|
+
carries each changed package's install scripts
|
|
171
|
+
- **Fix recipes** (`lib/fix/`, `penthera fix`): deterministic, local fixes for
|
|
172
|
+
common findings, printed as unified diffs. `penthera fix --plan` plans fixes
|
|
173
|
+
for a fresh repo scan or an earlier `-o` report; `penthera fix --apply <id>`
|
|
174
|
+
applies one after a y/N prompt (or `--yes`), then re-scans to verify. Recipes:
|
|
175
|
+
security headers (Next.js, Express, Fastify, Hono), cookie flags, CORS
|
|
176
|
+
wildcard to an allowlist from `CORS_ALLOWED_ORIGINS`, a rate-limit stub on
|
|
177
|
+
login/auth routes, and a hardcoded secret moved to an env var with
|
|
178
|
+
`.env.example` updated (always with the owner action to rotate it)
|
|
179
|
+
- `applyDiff()` refuses paths outside the repo (symlinks included), `.git`,
|
|
180
|
+
and dirty or non-git trees unless `--allow-dirty`, and writes nothing unless
|
|
181
|
+
every hunk applies. Planning never writes; nothing is committed or pushed
|
|
182
|
+
- Recipes edit only at exact anchors and return no plan when the anchor is
|
|
183
|
+
missing, instead of a risky diff
|
|
184
|
+
- Optional `--fix-model <name>` fallback for findings no recipe matches. It
|
|
185
|
+
talks only to Ollama on `127.0.0.1:11434`, is off by default, and labels its
|
|
186
|
+
output `confidence: "needs-human-review"`, `source: "local-model"`
|
|
187
|
+
- Fixtures for Next.js, Express, Fastify and Hono under `tests/fixtures/fix/`
|
|
188
|
+
- `detectFramework()` is now exported from `lib/whitebox/frameworks.js`
|
|
189
|
+
- **Audience reports** (`--audience developer|owner|auditor`): developer gets
|
|
190
|
+
findings with file:line, fix recipe ids or diffs, and sources; owner gets a
|
|
191
|
+
plain-language summary, what to do first, owner actions and the trend from
|
|
192
|
+
memory; auditor gets scope and method (linking `docs/METHODOLOGY.md`),
|
|
193
|
+
confidence labels with provenance per finding, egress and inconclusive
|
|
194
|
+
probes, suppressions with who and why, and NIS2 and OWASP mapping tables.
|
|
195
|
+
The default report is unchanged
|
|
196
|
+
- **User templates** (`--report-template file.md`): `{{a.b}}`,
|
|
197
|
+
`{{#each}}`, `{{#if}}`/`{{else}}`, nothing else. Values are HTML- and
|
|
198
|
+
Markdown-escaped; no helpers, code, includes or prototype access. Written from
|
|
199
|
+
scratch (`src/report/template.js`) and fuzz-tested against injection
|
|
200
|
+
- **Fix timeline** in the audience reports: found → fixed → verified with time
|
|
201
|
+
to fix, from an agent loop run (`loopRun`) or memory fix events
|
|
202
|
+
(`lib/memory/history.js`, also the owner report's trend)
|
|
203
|
+
- **Evidence bundle** (`--evidence <dir>`, `--sign-key <ssh-key>`): JSON,
|
|
204
|
+
Markdown, SARIF, the three audience reports, a custom template report, the
|
|
205
|
+
readiness report and SBOM when requested, and `manifest.json` (tool version,
|
|
206
|
+
command line with secrets redacted, timestamp, target, git commit, SHA-256 of
|
|
207
|
+
every file). Signing uses `ssh-keygen -Y sign -n penthera-evidence`; no new
|
|
208
|
+
dependency. `penthera evidence verify <dir> [--allowed-signers <file>]`
|
|
209
|
+
recomputes every hash, rejects changed, missing, extra and symlinked files,
|
|
210
|
+
and checks the signature. See `docs/evidence.md`
|
|
211
|
+
- **`penthera agent --loop`** (`src/agent/`): the local scan → triage → plan →
|
|
212
|
+
patch → verify → learn loop. Fixes are applied one at a time on a local
|
|
213
|
+
branch `penthera/fix-<yyyymmdd-hhmm>`, verified by a re-scan (and the
|
|
214
|
+
project's tests with `--run-tests`), committed when verified and reverted
|
|
215
|
+
when not. Every diff needs `y/n/skip/quit` approval; `--auto low` auto-applies
|
|
216
|
+
only recipes memory shows verified 3+ times with no failures on the
|
|
217
|
+
framework. Stops when nothing fixable is left or at `--max-iterations`
|
|
218
|
+
(default 5). `-o` writes a `loopRun` JSON (iterations, fixes, time per step),
|
|
219
|
+
also appended to memory as a new `loop_run` event
|
|
220
|
+
- The loop runs git only through an allow-list of local subcommands with
|
|
221
|
+
`protocol.allow=never`, no lazy fetch and the repo's hooks disabled; it never
|
|
222
|
+
pushes, fetches or opens pull requests. Scans run in one offline egress
|
|
223
|
+
context (the `--url` host only; Ollama on 127.0.0.1 only with
|
|
224
|
+
`--fix-model`). It refuses a dirty tree or detached HEAD unless
|
|
225
|
+
`--allow-dirty`, and Ctrl-C leaves only verified commits on the fix branch
|
|
226
|
+
|
|
227
|
+
### Docs
|
|
228
|
+
|
|
229
|
+
- Sharper positioning: "the routine work of a security team, on your own
|
|
230
|
+
machine". The README now opens with what Penthera does for you, why you can
|
|
231
|
+
trust it, and a factual table of how it fits next to Socket, Snyk, GitHub,
|
|
232
|
+
OWASP ZAP and Anthropic's OSS Scanner. The package, plugin, skill and
|
|
233
|
+
repository descriptions match.
|
|
234
|
+
- Funding and partnership drafts under `docs/funding/`: an NLnet application
|
|
235
|
+
draft, GitHub Sponsors tiers, a partner brief, and a due diligence checklist.
|
|
236
|
+
- CONTRIBUTING: commits are signed off under the Developer Certificate of Origin.
|
|
237
|
+
- **`--offline`**: the scan contacts only the target. Recon is skipped, the
|
|
238
|
+
Retire.js check uses the vendored database snapshot, and every other host is
|
|
239
|
+
refused by the HTTP client (redirects may stay within the target's
|
|
240
|
+
registrable domain). Groundwork for the local agent loop.
|
|
241
|
+
- **Vendored Retire.js database** (`lib/data/retire-jsrepository.json.gz`,
|
|
242
|
+
72 KB gzipped) with source URL, date and SHA-256 in a meta file.
|
|
243
|
+
`npm run refresh:retire-db` updates it at release time, and
|
|
244
|
+
`npm run refresh:retire-db -- --check` reports drift from upstream. Online
|
|
245
|
+
scans fall back to it when the live download fails.
|
|
246
|
+
- **Third-party egress report**: every scan lists the hosts it contacted
|
|
247
|
+
besides the target, in the terminal summary and in a "Network egress" section
|
|
248
|
+
of the Markdown report (`result.egress` in JSON).
|
|
249
|
+
- **`--user-agent <ua>`** to override the new default User-Agent.
|
|
250
|
+
|
|
251
|
+
### Changed
|
|
252
|
+
|
|
253
|
+
- Every request now sends `User-Agent: penthera/<version>
|
|
254
|
+
(+https://github.com/danoszz/penthera)` instead of Node's default (#7;
|
|
255
|
+
first added by @Nurana100 in #20, our first outside contribution).
|
|
256
|
+
- Probe failures (timeouts, connection errors, refused hosts) are recorded as
|
|
257
|
+
`result.errors[]` (`{ probe, url, message, count }`). The terminal summary
|
|
258
|
+
shows "N probes inconclusive", and the Markdown report lists them under
|
|
259
|
+
"Inconclusive probes" (#8).
|
|
260
|
+
- All network calls go through one client in `src/utils/http.js`, which owns
|
|
261
|
+
timeouts, the User-Agent and egress policy. The per-module fetch wrappers in
|
|
262
|
+
the crawler, injection, fuzzer, template, recon, parameter, Retire.js and
|
|
263
|
+
adaptive-probe modules are gone.
|
|
264
|
+
- **Local learning store** (`lib/memory/`), the memory behind the v1.4 local
|
|
265
|
+
loop. `--memory` records each scan under `~/.penthera/memory/<project-id>/`
|
|
266
|
+
(or `PENTHERA_HOME`) as an append-only, hash-chained event log, then uses it
|
|
267
|
+
to suppress findings marked as false positives and to rank findings within a
|
|
268
|
+
severity. Suppressed findings are listed in their own section with who
|
|
269
|
+
suppressed them and why. Memory is never read from the scanned repo and
|
|
270
|
+
nothing in it is ever executed; a broken chain means memory is not applied.
|
|
271
|
+
See [docs/local-loop.md](docs/local-loop.md) for the threat model
|
|
272
|
+
- `penthera memory show | verify | forget [--all] | suppress <id> --reason <text>`
|
|
273
|
+
- Optional repo file `penthera.suppress.json` for shared suppressions. Every
|
|
274
|
+
finding it hides is labelled "suppressed by repo file" with its reason
|
|
275
|
+
|
|
7
276
|
## [1.2.0] - 2026-10-19
|
|
8
277
|
|
|
9
278
|
The first step toward securing the AI toolchain itself: catch AI provider keys,
|