Skip to content

v0.68.0

Choose a tag to compare

@github-actions github-actions released this 29 May 21:15
· 4368 commits to main since this release
0da18f7

Note: The v0.68.0 Windows agent crash-loops on startup — see v0.68.2. Self-hosters on v0.67.1 must upgrade via v0.68.1 (migration-checksum fix) and should land on v0.68.2+. This page documents what v0.68.0 introduced.

Added

  • PAM elevation discovery + actuation (Privileged Access Management). A Windows ETW Microsoft-Windows-LUA subscriber observes UAC consent.exe prompts and posts elevation_requests rows (flow_type='uac_intercept') to the API via a new POST /agents/:id/elevation-requests endpoint, with a bounded offline JSONL queue for API-unreachable windows (Track 3, discovery-only). A paired UAC elevation actuator (SendInput into consent.exe on the secure desktop) plus the admin POST /devices/:id/actuate-elevation route queues the elevation command (Track 5). The actuate-elevation route is gated OFF by default (PAM_ACTUATOR_ENABLED !== 'true' → 403); do not enable in production until the deferred Track-6 JIT-credential and separation-of-duties hardening lands (#959, #960).
  • Global Current/All-orgs scope toggle next to the org picker. A single scope pill (orgScope: 'current' | 'all', persisted) replaces per-page org toggles; in All-orgs mode the registerOrgIdProvider chokepoint returns null so fetchWithAuth skips orgId auto-injection and the server responds across every accessible org. The pill is hidden when only one org is accessible, and picking a specific org flips scope back to Current (#985).
  • Per-row Update and Uninstall actions on the device-detail Software tab. Both queue real software_update / software_uninstall commands through the existing device_commands pipeline (new POST /devices/:id/software/update and .../uninstall routes, requiring devices.execute + satisfied MFA). Per-OS package-manager shims cover Windows (winget), macOS (brew), and Linux (apt-get/dnf/yum/zypper/pacman), with Apple-published apps and protected Linux packages refused. "Already up to date" outcomes map to success (#974).
  • Exit-code → severity mapping editor in the new-script / edit-script web form. A collapsible "Exit Code Severity" section with add/remove rows and per-row + duplicate-code validation surfaces the server-side mapping from #798 that was previously reachable only via curl (#941).
  • Off-region backup upload + automated restore verification. scripts/ops/offsite-backup.sh uploads the Postgres dump (plus a db/latest.dump pointer) to an off-region S3-compatible bucket; scripts/ops/restore-test.sh pulls latest.dump, restores into a throwaway dockerized Postgres, asserts a sane devices row count, and alerts on failure. Documented in DISASTER_RECOVERY.md (#977).
  • Anomaly alerting for failed logins, enrollments, and command dispatch. Three Prometheus counters (breeze_failed_logins_total, breeze_agent_enrollments_total, breeze_commands_dispatched_total) with prod-redacted tenant labels, plus FailedLoginSpike / EnrollmentSpike / CommandDispatchSpike alert + recording rules. Tenant labels reuse the existing METRICS_INCLUDE_ORG_ID opt-in policy (#975).
  • Breeze Assist Helper token delivery over the agent's authenticated IPC channel (Phase 1). A new least-privilege assist agent role and dedicated helper_token_update message push the per-device helper_auth_token to the in-memory Helper instead of relying on the world-readable agent.yaml, gated by the agent's IPC peer-auth (PID→SID/UID + binary-hash allowlist). Phase 1 still writes the token to agent.yaml and the Helper falls back to it, so there is no version-skew lockout; the file leak is closed in a later Phase 2 (#996).

Fixed

  • Huntress integration sync was silently broken — imported no data while the integration status falsely read success. Four bugs fixed: switched auth from Bearer/X-API-Key to HTTP Basic (base64(KEY:SECRET)), corrected the endpoint path from /incidents to /incident_reports, coerced Huntress's numeric id/account_id/agent_id fields in firstString (previously dropped 100% of records as null-id), and committed the failure status via a fresh withSystemDbAccessContext so a failed sync no longer rolls back its own lastSyncStatus='error' write and masks the outage (#986).
  • /security/firewall, /security/encryption, /security/password-policy, /security/admin-audit, and /patches now honor the ?orgId= query parameter they appeared to accept but silently ignored, so the global Current/All-orgs toggle narrows them correctly for MSPs (#973).
  • POST /update-rings (custom update ring create) returned 400 "orgId is required" for partner/MSP users because the handler resolved org only from the JSON body while the web client passes it as ?orgId=. Create now falls back to the query-string orgId, matching the GET handler and routing through the same canAccessOrg() check (#987).
  • GET /devices list mapper silently dropped watchdogStatus and mainAgentSilentSince, so the amber "Agent silent (watchdog OK)" badge from #862 never rendered end-to-end on the Devices list. The two fields are now copied onto the JSON output (#940).
  • agent.yaml is once again readable by the Breeze Assist Helper. The SR-001..SR-024 hardening (#568) had tightened the config so the logged-in user (which the Helper runs as) was denied, producing a misleading "requires the Breeze agent" message. POSIX perms relax to 0755 dir / 0644 agent.yaml and Windows adds a BUILTIN\Users:Read ACE, while secrets.yaml (which holds the full agent/watchdog tokens and mTLS keys) stays SYSTEM + Administrators only on its own SDDL (#988).
  • PowerShell event-log queries now emit UTF-8. On Polish (and other non-Latin-locale) Windows machines, Device Logs showed every diacritic corrupted to � because PowerShell wrote stdout in the console OEM codepage. Get-WinEvent commands are now prefixed with [Console]::OutputEncoding=[System.Text.Encoding]::UTF8; in both the collector and the interactive event-log viewer (#980).
  • Audit hash-chain migrations failed the v0.67.x EU upgrade with invalid input syntax for type bytea on real data. The chain now hashes the canonical payload via convert_to(payload, 'UTF8') instead of <text>::bytea (which ran backslash escapes through the bytea parser) at every hashing site — trigger fn, verify_chain, backfill loops, and retention re-anchor. Byte-identical to the prior form for backslash-free payloads, so every existing checksum stays valid (#994).
  • Org-scope pill now refreshes all list pages on flip. PR #985's pill only live-refetched pages with orgScope in their fetch deps; the pill now reloads (awaiting waitForPendingRefresh() first, the #950 in-flight-refresh guard) so every list page picks up the new scope (#989, #990).
  • OrgSwitcher org/site switching awaits any in-flight tokenRefreshInFlight before reloading, fixing a P1 race against the background /auth/refresh that could clear the session (#950, #953, #956, #958).
  • Self-host docker compose up -d no longer fails with invalid reference format. .env.example now ships working tag-pinned image defaults (Breeze refs resolve via ${BREEZE_VERSION}, bumped from a stale 0.1.3) with inline comments on the digest-pinned upgrade path; deploy/.env.example keeps its strict placeholders (#961, #962).
  • JWT log noise suppressed when a bearer token is structurally not a JWT. Routes that accept multiple bearer formats (API key, agent token, enrollment/viewer token) no longer log jose's JWSInvalid/JWTInvalid structural errors as stderr noise; genuine signature/expiry/claim failures still log at debug (#965).
  • elevation_requests added to DEVICE_ORG_DENORMALIZED_TABLES and DEVICE_SITE_DENORMALIZED_TABLES, so POST /devices/:id/move-org rewrites their denormalized org_id/site_id and active PAM elevation requests aren't stranded under the old tenant (#942).
  • Corrected the misleading TRUSTED_PROXY_CIDRS empty-list error hint, which suggested broad private CIDRs (10.0.0.0/8, 172.16.0.0/12) that the validator rejects two checks later — private proxies must be pinned to exact hosts (/32//128) (#995).

Security

  • May 2026 security-review batch-2 fixes. Agent-auth skip carve-out tightened from an open-ended regex to an exact-match allowlist so nested /approve//deny paths enforce agent auth (#10); dead optionalAuthMiddleware/eitherAuthMiddleware (an auth-bypass foot-gun) removed (#9); the hand-maintained secret strip-list replaced with a drift-proof isSecretYAMLKey predicate that also catches backup_s3_* (#6); secrets.yaml chmod-enforce failure made fatal (#8); DNS-provider sync routed through the DNS-pinning safeFetch with an !IS_HOSTED-gated allowPrivateNetwork opt-in, plus a fix for a Critical IPv4-mapped-IPv6 metadata bypass (http://[::ffff:a9fe:a9fe]/) in the shared SSRF guard that hardens all safeFetch callers (#5); access_reviews partner-axis rows converted from org-only RLS to Shape-4 dual-axis (#7); the misleading ENABLE_2FA warning corrected plus a non-fatal config-validator warning (#3); and the PAM actuate-elevation route gated OFF by default (#2) (#997).

Full Changelog: v0.67.1...v0.68.0