You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Verified findings from a 6-lens adversarial sweep. One critical (HostConfig.Capabilities
allowlist bypass) was investigated and REJECTED as a false positive — the field exists in
no Docker release (v20.10/v24/master all lack it; PR #38380 reverted pre-release).
- 🔒 security(filter): zero-padded numeric UIDs ("00","000:5") no longer bypass
require_non_root_user / allow_root_user — parse the UID, treat any 0 as root
- 🔒 security(config): wide-open dedicated admin listener (non-loopback plaintext, no
CIDR allowlist) is now a validation error, gated by new admin.listen.insecure_allow_wide_open
- 🐛 fix(reload): verifyBundle reads signature_path from the CANDIDATE config, not the
last-applied one — rotating the bundle no longer wedges every subsequent reload
- 🐛 fix(config): register allow_sysctls + image_trust.verify_timeout SetDefaults so their
SOCKGUARD_* env vars are honored (Viper only unmarshals registered keys)
- 🐛 fix(filter): oversized /nodes/*/update and /build bodies return 413, not 403
- ⚡ perf(proxy): drain upstream inspect responses before close (ownership + visibility)
so daemon keep-alive connections are reused
- 📝 docs(configs): drop non-existent allowed_users from cis + gitlab-runner exec comments
- ✅ test: zero-padded UID boundaries, candidate signature_path, env-var defaults, node/build 413
- 📝 docs: admin.listen.insecure_allow_wide_open in configuration.mdx + env table; roadmap refresh
Deferred to roadmap: stale per-profile in-flight gauge on profile removal; SecurityOpt
label=/systempaths= passthrough (needs policy design).
Copy file name to clipboardExpand all lines: CHANGELOG.md
+10Lines changed: 10 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,8 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
8
8
## [Unreleased]
9
9
10
+
### Security
11
+
12
+
-**Zero-padded numeric UIDs can no longer bypass root-user enforcement.**`require_non_root_user` (container create) and `allow_root_user: false` (exec) compared the user field to the exact string `"0"`, but Docker parses `Config.User` numerically — so `"00"`, `"000"`, or `"0000:5"` all run as root while slipping past the check. Both inspectors now parse the UID and treat any value resolving to 0 as root.
13
+
-**A wide-open dedicated admin listener is now a validation error, not just a startup warning.** A non-loopback plaintext admin listener with no `clients.allowed_cidrs` exposes candidate-YAML submission and policy metadata with no authentication and no IP backstop. Validation now rejects that shape unless the operator sets `clients.allowed_cidrs`, configures `admin.listen.tls`, or explicitly acknowledges the exposure with the new `admin.listen.insecure_allow_wide_open: true`.
14
+
10
15
### Fixed
11
16
17
+
-**A hot reload that rotates `policy_bundle.signature_path` no longer wedges every subsequent reload.** Bundle verification resolved the signature file from the last-applied config instead of the candidate, so changing `signature_path` (which is intentionally reload-mutable) loaded the wrong bundle, failed the digest check, and — because the active config only advances on success — left the operator permanently stuck until a restart. Verification now reads the path from the candidate config.
18
+
-**`SOCKGUARD_REQUEST_BODY_CONTAINER_CREATE_ALLOW_SYSCTLS` and the `image_trust.verify_timeout` env vars are no longer silently ignored.** Three `request_body` keys were missing their `SetDefault` registration, and Viper only unmarshals registered keys — so configuring those fields purely through their `SOCKGUARD_*` env vars (no config file) had no effect. All three are now registered.
19
+
-**Oversized `POST /nodes/{id}/update` and `POST /build` request bodies now return `413` instead of `403`,** matching every other body-limited inspector (a policy `403` implied the request was forbidden by rule rather than too large).
12
20
-**Release images now carry real `commit` and `built` metadata.** The release workflow's Docker build only passed the `VERSION` build arg, so `sockguard version` in published images reported `commit unknown / built unknown`. The workflow now passes `COMMIT` (the tagged SHA) and `BUILD_DATE` (UTC build timestamp) through to the existing ldflags wiring.
13
21
-**The container-label ACL exclusivity warning now fires once per process instead of on every hot-reload.** It was wired into the handler-chain build, which reruns on each config reload, so long-running deployments with reload enabled accumulated duplicate warnings. The warning is now gated by a process-lifetime guard (and finally has test coverage for both the enable-check and the once semantics).
14
22
-**Coalesced inspect-cache waiters now honor their own context.** A request that joined an in-flight upstream inspect blocked unconditionally until that inspect finished — a slow daemon could pin waiter goroutines past their own deadlines. Waiters now return `ctx.Err()` promptly on cancellation while the in-flight resolve (and its cache fill) continues for future callers.
@@ -17,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
17
25
### Changed
18
26
19
27
-**Test coverage for review-flagged gaps:** legacy (map-format) Docker filter encoding through the ownership and visibility rewrites end-to-end, the visibility meta-cache's one-inspect-per-TTL-window behavior, admin path-normalization variants on the policy-version interceptor (the validate interceptor already had them), and double-encoded `%252f` admin paths pinning the fail-closed pass-through. Corrected the visibility meta-cache code comment and the 1.3.0-rc.2 changelog wording: the cache accelerates repeated single-resource reads — list responses are filtered from their own payload and never inspect upstream.
28
+
-**Upstream inspect responses are now drained before close** on the ownership and visibility owner-isolation paths, so idle keep-alive connections to the daemon are reused instead of discarded after each inspect.
29
+
-**Corrected misleading exec comments in the `cis-docker-benchmark` and `gitlab-runner` presets** that referenced a non-existent `allowed_users` field; exec identity is controlled by `allow_root_user` and the argv `allowed_commands` allowlist.
Copy file name to clipboardExpand all lines: README.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -461,9 +461,9 @@ LinuxServer's socket-proxy env surface is already Tecnativa-compatible for the b
461
461
462
462
| Tier | Theme |
463
463
|---|---|
464
-
| Security hardening (v1.x) | Continued mutation-test hardening of the rule-evaluation core and config validators; swarm `ContainerSpec.User` / `Privileges` enforcement parity with container create; wide-open admin listener promoted from startup warning to error behind an explicit opt-in flag |
464
+
| Security hardening (v1.x) | Continued mutation-test hardening of the rule-evaluation core and config validators; swarm `ContainerSpec.User` / `Privileges` enforcement parity with container create; `HostConfig.SecurityOpt` `label=`/`systempaths=` policy evaluation (currently passed through) |
465
465
| Policy refinement (v1.x) | Multiple frontend listeners on the main proxy, named rule path aliases |
466
-
| Internals (v1.x) | Code-review backlog: collapse the config → filter-options → policy translation layers behind a single source of truth (generated Viper defaults); allocation-free rate-limit bucket state (packed `atomic.Uint64`); profiling-gated JSON redaction fast path |
466
+
| Internals (v1.x) | Code-review backlog: collapse the config → filter-options → policy translation layers behind a single source of truth (generated Viper defaults); allocation-free rate-limit bucket state (packed `atomic.Uint64`); profiling-gated JSON redaction fast path; clear per-profile in-flight gauges when a hot reload removes the profile |
0 commit comments