Dependabot flagged four picomatch vulnerabilities in
web/package-lock.json:
#8 GHSA-?, ReDoS via extglob quantifiers
#9 GHSA-?, ReDoS via extglob quantifiers (related to #8)
#10 CVE-2026-33672 / GHSA-3v7f-55p6-f55p, method injection via
POSIX character classes (related; affecting < 2.3.2)
#11 CVE-2026-33672 / GHSA-3v7f-55p6-f55p, method injection via
POSIX character classes — same advisory as #10, separate
Dependabot row because it surfaces against a second copy
of picomatch in the dep tree
All four close on the same fix: every resolved picomatch instance
must be >= 4.0.4 (or >= 3.0.2, or >= 2.3.2 — the patch shipped on
all three release lines). Pre-fix the lockfile carried at least
two vulnerable copies:
node_modules/picomatch v2.3.1 (vuln)
node_modules/vitest/node_modules/picomatch v4.0.3 (vuln for #11)
node_modules/vite/node_modules/picomatch v4.0.4 (ok)
node_modules/tinyglobby/node_modules/picomatch v4.0.4 (ok)
Reachability check before fixing:
- picomatch is a build-time glob-matching tool (used by
tailwindcss → readdirp/anymatch/micromatch chain, plus by
vite + vitest internals).
- All instances in our tree are dev=true. None are bundled into
the React production output (web/dist/assets/*.js) — that's
just the React SPA, no node_modules at runtime.
- The CVE only affects code that processes UNTRUSTED glob
patterns. Our build pipeline only globs operator-controlled
file patterns (TSX source files, Tailwind 'content' globs).
Not network-reachable.
So the CVE was not reachable from any shipped certctl artefact.
Fix anyway because the alerts are noise.
Fix mechanism: add an npm 'overrides' entry pinning picomatch to
^4.0.4 across all consumers. npm collapses every transitive
picomatch resolution to the override, so the lockfile shrinks from
4 picomatch entries to 1, all on v4.0.4 (patched).
Verification:
npm install --package-lock-only → up to date, 0 vuln
npm audit → found 0 vulnerabilities
Diff: 2 files, 7 insertions / 43 deletions (net negative — the
override de-duplicates the picomatch tree).
Closes: GHSA-3v7f-55p6-f55p, CVE-2026-33672 (alerts #10, #11) +
the two related ReDoS picomatch alerts (#8, #9)
Closes Dependabot alerts #12 (CVE — arbitrary file read via Vite dev
server WebSocket), #13 (CVE-2026-39364 — server.fs.deny bypassed with
?raw / ?import&raw / ?import&url&inline query suffixes), and #14 (path
traversal in optimized-deps .map handling). All three live in the vite
DEV server only — vite build (production output) is unaffected. All
three share the same advisory range '>= 8.0.0, <= 8.0.4' → fixed in
8.0.5; npm picked the latest 8.x patch (8.0.10).
Real-world exposure for certctl was low: web/package.json's 'dev: vite'
script has no --host flag, so the default binding is localhost
(127.0.0.1). Devs who manually run 'vite --host' for cross-machine
testing were exposed to the same-LAN attack vector; this closes it.
Manifest change: bumped the constraint from '^8.0.0' to '^8.0.10' to
document the security floor in package.json itself (the caret already
permitted 8.0.10, but pinning the floor higher prevents an accidental
downgrade if a future 'npm install' somehow re-resolves to a vulnerable
8.0.0-8.0.4). Lockfile change: 17 packages removed + 18 changed —
mostly transitive vite-internal modules (rolldown, oxc-* etc.) that
shifted around between 8.0.0 and 8.0.10.
Verified locally:
- 'npm install vite@^8.0.5 --save-dev' completed cleanly.
- 'vite build' produces the same web/dist/ output (668 modules
transformed, 35.30 kB CSS / 918.04 kB JS — same shape as pre-
upgrade).
- vitest run wasn't completed in the sandbox (test runner hung in
the disk-pressure environment); CI will run it on push.
Engineering history: this is a cross-cutting deps bump that lives
outside the ACME-Server-N phase plan.
Backend hardening:
- Fix 6 nginx.go non-constant format string build errors
- Add validation.go with hostname, PEM, and enum validators
- Apply input validation to all POST/PUT handlers (certificates,
agents, CSR, policies, teams, owners, targets, issuers)
- Fix unchecked JSON decode in TriggerDeployment handler
Frontend (Vite + React + TypeScript):
- Migrate from single-file SPA to proper build pipeline
- 7 pages: Dashboard, Certificates (list+detail), Agents, Jobs,
Notifications, Policies, Audit Trail
- TanStack Query for server state with auto-refetch intervals
- Certificate detail with version history and renewal trigger
- Job cancellation, status/type filtering, expiry countdowns
- Reusable components: DataTable, StatusBadge, ErrorState, PageHeader
- Dark theme with Tailwind CSS, sidebar nav via React Router
Server integration:
- Go server serves web/dist/ (Vite output) with SPA fallback
- Falls back to web/index.html for legacy mode
- .gitignore updated for web/node_modules/ and web/dist/
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>