Releases: CodesWhat/sockguard
v1.4.0-rc.1
release: v1.4.0-rc.1
v1.3.0
v1.3.0-rc.3
Merge pull request #94 from CodesWhat/release/changelog-rc3 🔧 chore(release): date the 1.3.0-rc.3 changelog entry
v1.3.0-rc.2
v1.3.0-rc.2: code-review batch (PR #88) + changelog entry (PR #90)
v1.2.0
release: v1.2.0
v1.1.0
sockguard is a default-deny Docker socket proxy written in Go. It filters every request by HTTP method, path, and request body — so a compromised API consumer can't escalate through the socket.
🔐 sockguard v1.1.0 — image trust, wired end to end
v1.1.0 makes cosign image-trust verification real — it was policy-only scaffolding in v1.0.0 — and lands a 21-finding security audit across the request-inspection and read-side filters. Everything stays inside the frozen v1.x contract: no breaking config, CLI, env-var, metric, or admin-endpoint changes.
✨ Highlights
- 🔏 Cosign image-trust verification is now enforced end to end — keyed (PEM) and keyless (Fulcio + Rekor), with registry digest resolution and digest-pinned forwarding. It was a no-op before.
- 🛡️ 21 HIGH+MEDIUM audit findings closed, each with regression coverage — request-inspection bypasses, read-side isolation gaps, and config/admin hardening.
- 🧩 Swarm services now enforce container-create policy — capability allowlist, sysctl gate, and image trust all apply to the service
ContainerSpec. - 🔍 CodeQL
actionsanalysis enabled, and 20 OSSF / Go-vuln-DB advisories cleared via dependency bumps (govulncheckreports zero).
🔏 Image trust (end to end)
- New
internal/imagefetchresolves the image to its registry manifest digest, discovers the cosign signatures attached to it (classicsha256-<digest>.sigtag and OCI 1.1 referrers), reconstructs a Sigstore verification bundle, and binds every signature to the resolved digest before verifying — so a valid signature for one image can't be transplanted onto another. - Keyed (PEM) and keyless (Fulcio + Rekor, trust root fetched via TUF at startup) both verify through the existing sigstore-go stack.
- Verified images are digest-pinned (
registry/repo@sha256:…) before the request is forwarded, closing the verify→pull TOCTOU. require_rekor_inclusionnow defaults totruefor keyless verification.
🔒 Security audit (21 findings)
- Request inspection — plugin multipart-boundary inspection bypass closed; BuildKit
# syntax=external-frontend builds denied; gzip-bomb decompression cap on the build context; newallowed_runtimesallowlist forHostConfig.Runtime(blocks alternate-OCI-runtime profile escapes); empty/whitespace execUsernow treated as root. - Swarm parity —
POST /services/createand/services/*/updatenow enforce the same capability allowlist,allow_sysctlsgate, and image-trust verification as container-create. Swarm is no longer an unfiltered path to privilege. - Read-side isolation — visibility now gates container/image sub-resources (
logs/stats/top/changes/export/archive/attach, imagehistory/get); image/getexport is owner-filtered; the inspect cache no longer memoizes not-found verdicts; response redaction now coversHostConfig.Mounts[].Sourceand servicePreviousSpec. - Config / admin — signed-bundle verify-then-load TOCTOU closed and env vars can no longer override signed policy; PID-only unix-peer profile assignment rejected (PIDs are recycled); the dedicated admin TCP listener enforces the same
clients.allowed_cidrsbackstop as the main listener. - Supply chain — CodeQL
actionslanguage enabled for workflow static analysis;x/crypto/x/net/x/sysbumped to clear 20 advisories (all unreachable from sockguard's code paths; the post-bump scan is clean).
🧪 Quality
- Hardened the synthetic benchmark load generator — clean end-of-window shutdown (no more false "proxy error" reports) plus per-error-string counts for anomaly triage.
- De-flaked the rate-limit and request-ID-generator timing tests against a frozen clock. Test-only — the proxy binary is unaffected.
📥 Install
docker pull ghcr.io/codeswhat/sockguard:1.1.0Also published to docker.io/codeswhat/sockguard and quay.io/codeswhat/sockguard. Prebuilt binaries for linux/macOS · amd64/arm64 are attached below. Every image and tarball is cosign-signed — see the verification docs.
📦 ghcr.io/codeswhat/sockguard:1.1.0 · 📖 Documentation · 🔎 Full diff
v1.0.0
sockguard is a default-deny Docker socket proxy written in Go. It filters every request by HTTP method, path, and request body — so a compromised API consumer can't escalate through the socket.
🎉 sockguard v1.0.0 — first stable release
v1.0.0 ships the proxy contract that v1.0.0-rc.2 froze on 2026-05-16. Three small binary deltas land on top of the RC — a pinned Go toolchain, a sealed signature-verification edge case, and a sigstore bump. Everything else is non-binary hardening: new tests, CI workflows, policy presets, compose examples, and docs polish.
✨ Highlights
- 🏁 First stable release — the v1.x proxy contract is frozen.
- 🛡️ 12 bundled policy presets — 3 new: CIS Docker Benchmark, GitHub Actions runner, GitLab Runner.
- 🔐 Go toolchain pinned to 1.26.3 — clears 17 HIGH stdlib CVEs.
- 🧪 Phase A QA hardening — proxy-vs-daemon differential harness, real-
dockerdintegration tier, memory/goroutine soak tests, mTLS edge-case suite. - 📦 3 ready-to-run Docker Compose stacks under
examples/compose/.
🔒 Security
- Go toolchain pinned to
1.26.3via thetoolchaindirective ingo.mod; CI now readsgo-version-fileso the toolchain is a single source of truth. Clears 17 HIGH stdlib CVEs that opened against rc.2's stdlib in the weekly Grype scan. sigverify.VerifyKeylessno longer skips its issuer / SAN re-check on a nil certificate. An absent cert is now treated as a verification failure whenever issuer or SAN expectations are configured — if the cert can't be inspected, the expectation can't be honored, so the only safe answer is to reject.github.com/sigstore/sigstorebumpedv1.10.5→v1.10.6— cosmetic upstream OAuth success-page template fix; no behavior change in policy-bundle or image-trust.
🛡️ New presets & examples
| Preset | For |
|---|---|
cis-docker-benchmark.yaml |
Admission gate for the inspectable subset of CIS Docker Benchmark v1.6.0 Section 5. Non-compliant docker run is rejected with 403 before dockerd ever executes it. |
github-actions-runner.yaml |
Purpose-built for actions/runner self-hosted runners that spawn job + service containers. |
gitlab-runner.yaml |
Purpose-built for gitlab-runner with the Docker executor — rejects Privileged=true even if config.toml asks for it. |
Three matching compose stacks ship under examples/compose/ (each with docker-compose.yml, a sockguard.yaml overlay, and a security-tradeoff README.md). Total bundled presets is now 12.
🧪 Quality & testing
- Proxy-vs-daemon differential harness (
app/differential/) — 40+ path-evasion cases, a CL/TE request-smuggling axis, a JSON-decoder differential axis, and a newFuzzPathRoutingDifferentialtarget wired into per-PR / nightly / monthly tiers. - End-to-end suite against a real
dockerd(app/integration/) — drives sockguard as a process behind a live daemon and checks every shipped preset for allow/deny conformance, wired to a nightly CI job. - Memory / goroutine-leak soak (
scripts/soak.sh) plus a weekly 4 h CI run; slowloris and concurrent-hijack leak regressions. - mTLS / TLS edge-case suite —
internal/sigverifycoverage from 0 % to comprehensive; a weeklytestssl.shDAST probe of the TCP listener. - Downstream image-signature verification — a
verify-publishedCI job runs the exactcosign verifycommands published in the docs against every pushed image tag, catching docs-vs-pipeline drift.
🔧 Tooling & docs
gofmt -lCI gate added;govulncheck ./...added to the pre-push pipeline — the tree is vuln-clean.- New
/docs/cis-docker-benchmarkguide; widened/docs/security#known-limitations;/docs/presetsnow covers all 12 presets.
⬆️ Upgrading from 0.8.x
v1.0.0 carries the breaking YAML / CLI / metrics renames introduced in v1.0.0-rc.1 and the two-flag plaintext-TCP gate from v1.0.0-rc.2. Review those release notes before upgrading.
📥 Install
docker pull ghcr.io/codeswhat/sockguard:1.0.0Also published to docker.io/codeswhat/sockguard and quay.io/codeswhat/sockguard. Prebuilt binaries for linux/macOS · amd64/arm64 are attached below. Every image and tarball is cosign-signed — see verification docs.
📦 ghcr.io/codeswhat/sockguard:1.0.0 · 📖 Documentation · 🔎 Full diff
v1.0.0-rc.2
sockguard is a default-deny Docker socket proxy written in Go. It filters every request by HTTP method, path, and request body — so a compromised API consumer can't escalate through the socket.
sockguard v1.0.0-rc.2 — release candidate 2
⚠️ Pre-release. This is the candidate that froze the v1.0 proxy contract on 2026-05-16. For production use the stablev1.0.0.
⚠️ Breaking change
A non-loopback plaintext TCP listener now requires two insecure acknowledgments instead of one: listen.insecure_allow_plain_tcp (unencrypted transport) and the new listen.insecure_allow_unauthenticated_clients (any host that can reach the port can impersonate a client). One flag without the other is rejected at config validation, so the dangerous mode can't be reached by a single fat-fingered flag. The same applies to admin.listen.*. Existing plaintext non-loopback TCP configs must add insecure_allow_unauthenticated_clients: true (env: SOCKGUARD_LISTEN_INSECURE_ALLOW_UNAUTHENTICATED_CLIENTS).
🔄 Changed
request_body.exec.allowed_commandsentries are now glob-matched argv templates instead of exact strings. Each token follows the same dialect as path rules (*matches a run of non-slash characters,**matches any sequence), so an operator can allowlist an exec whose argv carries a variable run ID, timestamp, or generated path — e.g.["drydock", "finalize", "*"]— without enumerating every literal form. Tokens with no glob metacharacters keep matching exactly as before.- A rule whose
match.pathcontains a literal%is now a config-validation error instead of a startup warning — sockguard percent-decodes paths before matching, so such a pattern can never fire, and a silently dead rule is a security-intent gap.
🐛 Fixed
- Oversized request bodies on the exec, plugin, and swarm inspectors now return
413 Request Entity Too Largeinstead of403. All body inspectors now share one size-rejection contract.
🔒 Security
Hardening from the 2026-05-16 branch review:
- The visibility pattern-filter response buffer (
GET /containers/json,/images/jsonwithresponse.name_patterns/image_patterns) is now capped at 8 MiB — a larger upstream response is rejected with502instead of being buffered unbounded, closing an out-of-memory DoS. - The visibility middleware now honors rollout mode — an invisible single-resource inspect under
mode: warn/auditis forwarded with awould_denyverdict instead of a hard404, so operators can measure visibility-policy impact before enforcing. - The reverse-proxy and side-channel transports now set
ResponseHeaderTimeout: 30s— a Docker daemon that accepts a connection but never sends headers can no longer pin a goroutine indefinitely.
📥 Install
docker pull ghcr.io/codeswhat/sockguard:1.0.0-rc.2📦 ghcr.io/codeswhat/sockguard:1.0.0-rc.2 · 📖 Documentation · 🔎 Full diff
v1.0.0-rc.1
sockguard is a default-deny Docker socket proxy written in Go. It filters every request by HTTP method, path, and request body — so a compromised API consumer can't escalate through the socket.
sockguard v1.0.0-rc.1 — release candidate 1
⚠️ Pre-release. First v1.0 release candidate. It carries the breaking renames the v1.x line is built on — read the section below before upgrading. For production use the stablev1.0.0.
⚠️ Breaking changes
YAML schema renames — update configs and env var names before upgrading:
listen.tls.allowed_common_names→listen.tls.common_names(and the matchingallowed_dns_names,allowed_ip_addresses,allowed_uri_sans,allowed_public_key_sha256_pinslose theirallowed_prefix — same five renames apply toadmin.listen.tls.*).request_body.plugin.allow_ipc_host→allow_host_ipc;allow_pid_host→allow_host_pid.request_body.container_update.allow_devices→allow_all_devices.admin.max_body_bytes→admin.max_request_bytes.reload.debounce_ms/reload.poll_interval_ms(integer ms) →reload.debounce/reload.poll_interval(Go duration strings, e.g."250ms").
CLI flag rename: --deny-response-verbosity → --deny-verbosity.
Prometheus metric renames — update dashboards and alerts:
- Counter
sockguard_throttle_total→sockguard_throttle_requests_total; labelreason→reason_code. - The
rulelabel is dropped fromsockguard_http_denied_requests_total(its value was a zero-based ordinal that shifted on any rule edit). The rule index still appears in the structured audit log (matched_rule) and access log (rule).
🔒 Security
Dependency hardening — bumped eight indirect dependencies to close 11 OSSF Scorecard / OSV-Scanner findings. govulncheck now reports zero reachable and zero unreachable-but-imported vulnerabilities for the proxy binary. Notable: go-tuf/v2 (path-traversal + delegation-threshold + DoS fixes), sigstore/rekor (SSRF + nil-deref fixes), golang.org/x/net (HTTP/2 infinite loop), google.golang.org/grpc (authorization bypass).
Filter inspector hardening:
POST /containers/createnow always deniesHostConfig.VolumesFrom,UTSMode=host, a non-emptyCgroupParent,GroupAdd, andExtraHosts— five namespace-escape / privilege-escalation fields that were previously uninspected. No policy can opt out.POST /containers/{id}/execandPOST /swarm/unlockare now fail-closed when the request body can't be decoded.- Filter middleware applies a 30 s read deadline to the request body before inspection, so a slowloris-style stalled body can't pin an inspector worker.
Ownership & client-ACL hardening:
- The owner-label filter on list endpoints now replaces the entire
labelfilter rather than appending — closing a cross-tenant bypass where a client could OR inlabel=com.sockguard.owner=victimto widen the visible set. - Profile-lookup caches are now bounded (1024 entries, LRU); container-label resolution re-checks the container is still live before caching.
🔄 Changed
- New
RELEASING.mddocuments the end-to-end release process. serve --helpnow enumerates configuration precedence;--confighelp documents the missing-file fallback behavior.
📥 Install
docker pull ghcr.io/codeswhat/sockguard:1.0.0-rc.1📦 ghcr.io/codeswhat/sockguard:1.0.0-rc.1 · 📖 Documentation · 🔎 Full diff
v0.8.0
sockguard is a default-deny Docker socket proxy written in Go. It filters every request by HTTP method, path, and request body — so a compromised API consumer can't escalate through the socket.
sockguard v0.8.0 — hot reload, signed policy bundles & a control plane
This release turns sockguard's policy from a boot-time artifact into something you can stage, verify, and reload at runtime.
✨ Highlights
- 🔁 Hot reload of policy at runtime.
- ✍️ Signed policy bundles — cosign-verify the config before it's trusted.
- 🎛️ Admin control plane — validate candidate configs and read the running policy version.
- 🧪 Rollout modes — dry-run a tighter policy with
enforce/warn/audit.
🚀 Added
- Per-profile rollout modes via
clients.profiles[*].mode: enforce|warn|audit.warnandauditlet an operator stage a tighter policy without breaking callers — every deny gate consults the mode, the request is still served, the audit record carriesdecision=would_deny, and the deny/throttle counters gain amodelabel so dashboards can compare blocked vs. would-have-been-blocked volume side by side. Pre-auth admission gates (CIDR allowlist, identity-lookup failures) stayenforceregardless. - Hot reload of policy. With
reload.enabled: true, sockguard watches the config file viafsnotifyand also reloads onSIGHUP. Events are debounced; the reload pipeline parses, validates, compiles, and atomically swaps the handler chain on success — on any failure the running policy is preserved. Mutating an immutable field (listen.*,upstream.socket, trust material, …) is refused. Two new metrics surface the outcome:sockguard_config_reload_total{result=...}andsockguard_config_reload_last_success_timestamp_seconds. POST /admin/validate— an opt-in admin endpoint that runs a candidate YAML through the same parse/validate/compile pipeline assockguard validateand returns a structured JSON report. Running policy is never mutated. Useful as a CI gate before promoting a config.- Policy versioning. A monotonic generation counter ticks once at startup and once per successful reload, published via
GET /admin/policy/version(config SHA-256, rule/profile counts, signer + digest when bundles are enabled) and thesockguard_policy_versiongauge. - Optional dedicated admin listener. When
admin.listen.*is configured, the admin endpoints move to a separatehttp.Server— the main Docker-API listener never sees admin traffic and admin traffic never traverses the filter chain. - Signed policy bundles. With
policy_bundle.enabled: true, the on-disk YAML is untrusted until a cosign sigstore bundle confirms it. Keyed (PEM public keys) and keyless (Fulcio issuer + subject) verification, optional Rekor inclusion. Verified at startup and on every hot reload — a signature failure rejects the reload withreject_signatureand never touches running policy. Backed bysigstore-go, no new external dependency.
📥 Install
docker pull ghcr.io/codeswhat/sockguard:0.8.0📦 ghcr.io/codeswhat/sockguard:0.8.0 · 📖 Documentation · 🔎 Full diff
