WolfStack v25.9.2
v25.9.2: SECURITY — the built-in cluster secret no longer authenticates anyone who is not already a recorded peer
Reported privately by Dostxodjayev Abdullox (@squeeze440) on 2026-08-01,
with a proof of concept against the signed v25.9.0 release binary.
CWE-798 + CWE-306, CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H (9.8).
The cluster secret compiled into every build is published in this repo's
source. Until now any node that had not rotated to a per-install secret
accepted that constant as valid inter-node authentication from ANY source
address. require_auth() returns a 'cluster-node' identity for such a
request with no session, API key or account involved, so a remote
unauthenticated attacker could enumerate every container and then run
arbitrary commands as root inside any of them via
POST /api/containers/{runtime}/{id}/exec.
Fix: the built-in default is honoured only when the request arrives from
an address already recorded as a peer in nodes.json, taken from the
transport-level peer_addr() and explicitly NOT X-Forwarded-For /
realip_remote_addr (trusting those would hand the bypass straight back).
A single-node install has no recorded peers and refuses the constant
outright; an existing cluster keeps authenticating, so this ships without
needing a coordinated rotation.
Second, subtler path closed at the same time, found by the new regression
test rather than by review: load_cluster_secret() falls back to the
built-in constant whenever the custom-secret file is absent, empty or
unreadable, so on exactly the at-risk nodes BOTH the in-memory and
on-disk comparison branches already held the default. Guarding only the
third branch would have looked correct and changed nothing. Any
presentation of the published constant is now resolved through a single
decision point regardless of which internal slot holds those bytes; the
ordering requirement is documented at the call site.
All 14 call sites across api, vms, tui and the mTLS middleware take the
peer-scoped form; the peer-less helper is deleted so no caller can skip
the peer argument. Six new tests, including a named PoC regression and
IPv4-mapped-IPv6 canonicalisation for dual-stack listeners.
Nodes still on the default already raise a Compromise-severity finding
via secret_audit into System Check and the alert channels. Adds
SECURITY.md documenting the private reporting path — the reporter hit
the maintainer-only /security/advisories/new URL, which 404s without
write access.
Follow-up, tracked separately: container-exec and other shell sinks
should not accept cluster-secret auth at all (reporter's third
recommendation). That needs an audit of which endpoints peers
legitimately proxy and is deliberately not rushed into this release.
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.