WolfStack v25.9.3
v25.9.3: SECURITY hardening — a cluster secret alone no longer opens a shell, and the default-secret warning can no longer be dismissed
Completes recommendations 2 and 3 of the 2026-08-01 report by
Dostxodjayev Abdullox (@squeeze440). Recommendation 1 shipped in v25.9.2.
REC 3 — decouple command execution from the cluster-secret credential.
'A peer node legitimately proxying dashboard/API calls does not need
blanket authority to run arbitrary shell commands inside every
container.' New require_operator_auth() gates every endpoint that runs
caller-supplied commands or opens an interactive PTY:
- POST /api/containers/{runtime}/{id}/exec (the reported sink)
- POST /api/containers/{runtime}/{id}/updates/apply
- /ws/console/* and /ws/remote-console/* (interactive root shell)
- /api/vr-terminal/* (real PTY)
It accepts a genuine operator (session or API key), or a peer forwarding
an operator action — cluster secret PLUS X-WolfStack-Proxied and
X-WolfStack-Actor. It refuses the built-in default secret outright, even
from a recorded peer and even with WOLFSTACK_ACCEPT_DEFAULT_SECRET=1: the
published constant never reaches a shell, which is defence in depth on
top of the v25.9.2 peer gate. It also refuses a bare cluster secret with
no attribution — node-to-node state sync has no business opening a shell.
Attribution cannot be chained. node_proxy and remote_console_bridge stamp
the actor only when their OWN caller was a real operator, never when it
was another peer, so a secret-holder cannot bounce through a node's proxy
to manufacture operator identity. The receiving end independently
rejects an actor of 'cluster-node' as well.
Scope boundary, stated deliberately: read-only file listings that shell
out with an escaped path (files_lxc_browse, files_docker_browse) were NOT
moved onto this gate. They are file operations, not command execution;
gating them is scope creep with real breakage risk for cluster file
browsing.
REC 2 — a real rotation prompt instead of a soft warning. The credential
banner could be dismissed per session and only linked to Settings, which
is how a node runs for months on the published constant. The
cluster-secret-default finding is now non-dismissible and carries a
'Rotate now' button that runs the existing coordinated cluster-wide
rotation. Note the report's literal suggestion — retroactively auto-
generating a secret for existing installs — is unsafe as stated: an
un-migrated install is by definition multi-node, and rotating behind the
operator's back severs every peer. The forced prompt plus one-click
coordinated rotation achieves the intent without that.
remote_console_bridge's parameters are grouped into RemoteConsoleTarget
rather than growing to eight positional arguments.
Four new tests on the attribution rule. 1709 pass; clippy at baseline.
Co-Authored-By: CodeWolf paul@wolf.uk.com
Co-Authored-By: Wolf Software Systems Ltd paul@wolf.uk.com
Verifying this release
Each binary is signed via cosign keyless OIDC (no key distribution — signing identity is the GitHub Actions workflow itself, anchored to the Sigstore Fulcio CA and the Rekor transparency log) and ships with a SLSA build provenance attestation.
Verify the cosign signature:
cosign verify-blob \
--bundle wolfstack-x86_64.cosign.bundle \
--certificate-identity-regexp 'https://github.com/wolfsoftwaresystemsltd/WolfStack/\.github/workflows/release\.yml@.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
wolfstack-x86_64
Verify the build provenance:
gh attestation verify wolfstack-x86_64 --repo wolfsoftwaresystemsltd/WolfStack
Verify the SHA-256 checksum:
sha256sum -c SHA256SUMS
Artifacts
wolfstack-x86_64/wolfstack-aarch64/wolfstack-armv7— static musl binaries (Linux x86_64, ARM64 / Raspberry Pi 4+, and 32-bit ARM).wolfstack-<arch>.cosign.bundle— cosign signature bundle (cert + signature + Rekor entry).SHA256SUMS— checksums for both binaries.
For per-version history see CHANGELOG.md.