github PegaProx/project-pegaprox v0.9.9.1
v0.9.9.1 — security hardening + plugin frontend system

latest releases: v0.9.9.3, v0.9.9.2
7 hours ago

A focused follow-up release on top of v0.9.9. Security hardening across the API + plugin layer, first-class support for plugin frontend UIs (#381), three issues fixed from community reports (#380, #381, #382), and seven smaller patches that were sitting in the local queue.

Highlights

🔒 Security hardening

CSRF Origin matcher rewrite (#382). The 0.9.9 audit fix tightened CSRF on every JSON state-changing request — which broke for users behind Apache / nginx reverse proxies that don't forward X-Forwarded-Proto. The matcher now uses urllib.parse instead of string startswith() (closes a separate suffix-confusion bug we found while in the area — Origin: https://pegaprox.com.attacker.com would have slipped through) and is host-only / scheme-agnostic, which is what RFC 6454 actually cares about. Hardened against urlparse normalising tabs in scheme, non-http(s) schemes, userinfo confusion (http://evil@self), and explicit port mismatches. Fully pentested — 20 attack scenarios covered.

XXE defence on XCP-ng integration. XML parsing in pegaprox/core/xcpng.py switched from stdlib xml.etree to defusedxml — closes XXE / billion-laughs / external-entity expansion in iSCSI probe and RRD payloads.

Dependency CVE bumps. paramiko>=3.4.0 (CVE-2023-48795 Terrapin), urllib3>=2.0.7 (CVE-2023-43804 cookie-redirect leak).

OIDC / Entra re-authentication step-up. Sensitive ops (delete cluster, rotate creds, …) now require a TOTP code for OIDC admins. Previous behaviour treated session validity as sufficient for the re-auth gate, which made it a no-op for OIDC accounts — a stolen cookie passed. Admins without TOTP enrolled hit a clear requires_totp_setup fail-closed response with guidance.

Plugin HTML defence-in-depth. Status Page + Client Portal plugin pages refactored: strict CSP meta tag, single setHTMLSafe() audit point via detached <template> element, Number()-cast on every numeric CSS attribute interpolation to close residual CSS-attribute injection.

🧩 Plugin frontend system (#381)

First-class support for plugins that ship their own UI:

  • list_plugins() now exposes has_frontend and frontend_route from manifest.json so the dashboard can render a plugin tab without core changes per plugin.
  • Strict server-side route validation rejects external URLs, control characters (CRLF / null / tab), query / fragment injection, parent-segment traversal, and cross-plugin path hops. Manifest can declare relative form ('ui'/api/plugins/<id>/api/ui) or full path (/api/plugins/<id>/api/...); everything else is dropped.
  • Generic plugin frontend tab in the dashboard with sandboxed iframe — no allow-top-navigation, encodeURIComponent on theme / cluster params, defensive plugin-lookup fallback.
  • Security headers relaxed from X-Frame-Options: DENY / frame-ancestors 'none' to SAMEORIGIN / 'self' to enable the iframe contract — cross-origin clickjacking remains blocked. Validated with 12 months of production data from the Docker Swarm Manager plugin (#286).

Plugin authors targeting this hook: declare \"has_frontend\": true and \"frontend_route\": \"ui\" in your manifest.json, register your handler with register_plugin_route(plugin_id, 'ui', ...), and the tab appears.

💬 Community-reported fixes

  • #380 — disconnect / offline banner now shows the affected cluster and node names (truncated past three with "+N more") instead of a bare count. Translated into all 7 supported languages.
  • #374 — false "Capacity Outlook" warning on near-empty / single-node clusters: insights regression now requires R² ≥ 0.5 and slope-vs-current sanity bound before raising. Quiet on noise, loud on real signal.
  • #375 — VMs that lacked qemu-guest-agent at one point would never display agent values again, even after install. The _no_agent_vms skip-set now expires after 5 minutes and is purged on migrate.
  • #372 — PVE 9.1.x removed /cluster/ha/groups in favour of /cluster/ha/rules. HA monitor probes rules first and falls back to groups.
  • #376 — PBS "linked clusters" dropdown was showing all clusters instead of the user's tenant scope.

🎨 Polish

  • Theme-aware logo switching: Modern dark + Corporate dark → white pegasus; Corporate light → dark pegasus. PDF export uses dark pegasus for white-paper print.
  • New brand-asset variants in images/ (transparent + square) for press / sponsor use.

Acknowledgements

PegaProx is donation-funded — every line of code in this release is paid for by the community.

Platinum sponsors:

Thanks to @cklabautermann for the clear bug report on #382 (and posting the workaround that lets others unblock immediately), to @custosonlinux for the well-scoped PR proposal on #381, to @alfonsokuen for cross-linking #286 and contributing 12 months of operational data on the security-header call, and to @j0c00 for #374 + #375.

Want to back the next release? https://opencollective.com/pegaprox

Upgrading

Standard updater path applies — built-in updater picks up v0.9.9.1 from the next poll. Or:

./update.sh

For users behind a reverse proxy who hit CSRF validation failed after the v0.9.9 upgrade: this release fixes that on our side, no Apache / nginx config change needed.

— PegaProx team

Don't miss a new project-pegaprox release

NewReleases is sending notifications on new releases.