docker.io/library/eclipse-mosquitto
validated pin current tags: 2.0
eclipse-mosquitto — minimum capabilities AND read-only filesystem, derived by drop-test against the default invocation (the image's bundled config: listener 1883, anonymous local use). Capabilities trim 14 -> 2; the filesystem locks read_only with no tmpfs. capabilities: cap_drop:[ALL] + cap_add:[SETGID, SETUID] — the catalog's third privilege-drop shape: the BROKER ITSELF setuid/setgids to its mosquitto user in-process when started as root (not a gosu re-exec, not a master/worker fork). Dropping either cap fails startup with mosquitto's own "Error setting uid/groups whilst dropping privileges". The listener is the unprivileged :1883 — no NET_BIND_SERVICE under any sysctl posture. filesystem: read_only:true, tmpfs:[] — /mosquitto/data and /mosquitto/log are declared VOLUMEs (persistent in real deployments, never tmpfs; docker mounts them writable under read_only); /tmp derived not required. Both dimensions validated together; they apply as a unit. See criteria/docker.io/library/eclipse-mosquitto.md.
Use it
services:
eclipse-mosquitto:
image: docker.io/library/eclipse-mosquitto:2.0
cap_drop: [ALL]
cap_add: [SETGID, SETUID]
security_opt: ["no-new-privileges:true"]
read_only: true
This profile has multiple dimensions and is applied as a unit. Dimensions can interact — a capability can be required only because of a sibling read-only/tmpfs recommendation — so where they do, the minimum was derived under the sibling dimension's context. See the criteria doc and each dimension's recorded invocation below before applying them separately.
Dimension: capabilities
cap_drop: ALL + cap_add: SETGID, SETUID
| tool | container-sec-derive 0.7.0 |
|---|---|
| observer | drop-test |
| validated image | docker.io/library/eclipse-mosquitto@sha256:212f89e1eaeb… |
| validated date | 2026-07-16 |
| confidence | high |
| validated via | drop-test, ci-smoke |
| workload | profiles/workloads/mosquitto.sh |
| workload sha256 | f82b6e4cc300… |
| ig version | v0.51.0 |
Drop-test evidence
Each candidate removed in turn, the container restarted, and the workload re-verified.
| Removed | Verdict | Observed |
|---|---|---|
CHOWN | removable | correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root) |
DAC_OVERRIDE | removable | correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root) |
FSETID | removable | correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root) |
FOWNER | removable | correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root) |
MKNOD | removable | correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root) |
NET_RAW | removable | correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root) |
SETGID | required | container failed to start: Error setting groups whilst dropping privilege |
SETUID | required | container failed to start: Error setting uid whilst dropping privileges: Operation not permitted. |
SETFCAP | removable | correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root) |
SETPCAP | removable | correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root) |
NET_BIND_SERVICE | removable | correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root) |
SYS_CHROOT | removable | correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root) |
KILL | removable | correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root) |
AUDIT_WRITE | removable | correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root) |
Recorded invocation (run_config)
The minimum is valid for this invocation; a different user:, volume state, or entrypoint can change it.
| security_opt | no-new-privileges:true |
|---|
Workload script (profiles/workloads/mosquitto.sh)
#!/usr/bin/env bash
# Workload exerciser for the eclipse-mosquitto reference image.
#
# A real publish/subscribe round-trip via the in-image mosquitto_sub /
# mosquitto_pub clients: the subscriber runs in the foreground printing the
# one expected message to stdout, the publisher fires after a beat from the
# background. Probes exec as --user mosquitto so they cannot pollute a caps
# minimum, and NOTHING is written inside the container — a probe temp file
# under /tmp would derive the filesystem dimension's /tmp candidate
# falsely-required. The broker's own in-process privilege drop is asserted by
# the drop-test correctness check (see the criteria doc).
#
# Required env: MOSQUITTOCONTAINER (target container name or id).
set -euo pipefail
: "${MOSQUITTOCONTAINER:?MOSQUITTOCONTAINER must be set}"
C="${MOSQUITTOCONTAINER}"
deadline=$((SECONDS + 20))
# capture-then-match — `docker logs | grep -q` under pipefail SIGPIPEs the
# producer once the log outgrows the pipe buffer, turning a match into failure.
until grep -q "mosquitto version .* running" <<<"$(docker logs "$C" 2>&1)"; do
(( SECONDS >= deadline )) && { echo "broker never reported running" >&2; exit 1; }
sleep 1
done
got="$(docker exec --user mosquitto "$C" sh -c '
(sleep 1; mosquitto_pub -h 127.0.0.1 -t csd/probe -m csd-42 2>/dev/null) &
mosquitto_sub -h 127.0.0.1 -t csd/probe -C 1 -W 10 2>/dev/null' 2>/dev/null)"
if [ "$got" != "csd-42" ]; then
echo "pub/sub round-trip failed (got: ${got:-nothing})" >&2
exit 1
fi
Dimension: filesystem
read_only: true, no tmpfs
| tool | container-sec-derive 0.7.0 |
|---|---|
| observer | drop-test |
| validated image | docker.io/library/eclipse-mosquitto@sha256:212f89e1eaeb… |
| validated date | 2026-07-16 |
| confidence | high |
| validated via | drop-test, ci-smoke |
| workload | profiles/workloads/mosquitto.sh |
| workload sha256 | f82b6e4cc300… |
| ig version | v0.51.0 |
Drop-test evidence
Each candidate removed in turn, the container restarted, and the workload re-verified.
| Removed | Verdict | Observed |
|---|---|---|
/tmp | removable | correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root) |
Recorded invocation (run_config)
The minimum is valid for this invocation; a different user:, volume state, or entrypoint can change it.
| security_opt | no-new-privileges:true |
|---|
Workload script (profiles/workloads/mosquitto.sh)
#!/usr/bin/env bash
# Workload exerciser for the eclipse-mosquitto reference image.
#
# A real publish/subscribe round-trip via the in-image mosquitto_sub /
# mosquitto_pub clients: the subscriber runs in the foreground printing the
# one expected message to stdout, the publisher fires after a beat from the
# background. Probes exec as --user mosquitto so they cannot pollute a caps
# minimum, and NOTHING is written inside the container — a probe temp file
# under /tmp would derive the filesystem dimension's /tmp candidate
# falsely-required. The broker's own in-process privilege drop is asserted by
# the drop-test correctness check (see the criteria doc).
#
# Required env: MOSQUITTOCONTAINER (target container name or id).
set -euo pipefail
: "${MOSQUITTOCONTAINER:?MOSQUITTOCONTAINER must be set}"
C="${MOSQUITTOCONTAINER}"
deadline=$((SECONDS + 20))
# capture-then-match — `docker logs | grep -q` under pipefail SIGPIPEs the
# producer once the log outgrows the pipe buffer, turning a match into failure.
until grep -q "mosquitto version .* running" <<<"$(docker logs "$C" 2>&1)"; do
(( SECONDS >= deadline )) && { echo "broker never reported running" >&2; exit 1; }
sleep 1
done
got="$(docker exec --user mosquitto "$C" sh -c '
(sleep 1; mosquitto_pub -h 127.0.0.1 -t csd/probe -m csd-42 2>/dev/null) &
mosquitto_sub -h 127.0.0.1 -t csd/probe -C 1 -W 10 2>/dev/null' 2>/dev/null)"
if [ "$got" != "csd-42" ]; then
echo "pub/sub round-trip failed (got: ${got:-nothing})" >&2
exit 1
fi
Evidence & provenance
- Validation criteria — per-image scenarios and pass criteria
- Profile source in the repository
- Version history — every previously published pin, with the full profile as validated against it
Raw profile YAML
# eclipse-mosquitto — minimum capabilities AND read-only filesystem, derived
# by drop-test against the default invocation (the image's bundled config:
# listener 1883, anonymous local use). Capabilities trim 14 -> 2; the
# filesystem locks read_only with no tmpfs.
#
# capabilities: cap_drop:[ALL] + cap_add:[SETGID, SETUID] — the catalog's
# third privilege-drop shape: the BROKER ITSELF setuid/setgids to its
# mosquitto user in-process when started as root (not a gosu re-exec, not a
# master/worker fork). Dropping either cap fails startup with mosquitto's own
# "Error setting uid/groups whilst dropping privileges". The listener is the
# unprivileged :1883 — no NET_BIND_SERVICE under any sysctl posture.
#
# filesystem: read_only:true, tmpfs:[] — /mosquitto/data and /mosquitto/log
# are declared VOLUMEs (persistent in real deployments, never tmpfs; docker
# mounts them writable under read_only); /tmp derived not required.
#
# Both dimensions validated together; they apply as a unit. See
# criteria/docker.io/library/eclipse-mosquitto.md.
schema_version: "1.5"
image: docker.io/library/eclipse-mosquitto
reference_url: https://tmatens.github.io/container-security-profiles/profiles/docker.io/library/eclipse-mosquitto.html
applies_to:
tags: ["2.0"]
status: validated
dimensions:
capabilities:
cap_drop: [ALL]
cap_add: [SETGID, SETUID]
derivation:
tool: container-sec-derive
tool_version: "0.7.0"
sidecar_schema_version: "1.5"
observer: drop-test
validated_image: docker.io/library/eclipse-mosquitto@sha256:212f89e1eaeb2c322d6441b64396e3346026674db8fa9c27beac293405c32b3c
validated_date: "2026-07-16"
duration_seconds: 180
confidence: high
workload: profiles/workloads/mosquitto.sh
workload_sha256: "f82b6e4cc300fb546dc0d741f91c41f1267af7f58386e4bf35007d85ffab235b"
validated_via: [drop-test, ci-smoke]
observation_backend:
ig_version: v0.51.0
gadgets: []
run_config:
user: ""
command: []
entrypoint: ""
network: ""
pid: ""
devices: []
security_opt: ["no-new-privileges:true"]
mounts: []
env: []
drop_test:
checks:
- {removed: CHOWN, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
- {removed: DAC_OVERRIDE, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
- {removed: FSETID, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
- {removed: FOWNER, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
- {removed: MKNOD, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
- {removed: NET_RAW, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
- {removed: SETGID, required: true, observed: "container failed to start: Error setting groups whilst dropping privilege"}
- {removed: SETUID, required: true, observed: "container failed to start: Error setting uid whilst dropping privileges: Operation not permitted."}
- {removed: SETFCAP, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
- {removed: SETPCAP, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
- {removed: NET_BIND_SERVICE, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
- {removed: SYS_CHROOT, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
- {removed: KILL, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
- {removed: AUDIT_WRITE, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
filesystem:
read_only: true
tmpfs: []
derivation:
tool: container-sec-derive
tool_version: "0.7.0"
sidecar_schema_version: "1.5"
observer: drop-test
validated_image: docker.io/library/eclipse-mosquitto@sha256:212f89e1eaeb2c322d6441b64396e3346026674db8fa9c27beac293405c32b3c
validated_date: "2026-07-16"
duration_seconds: 60
confidence: high
workload: profiles/workloads/mosquitto.sh
workload_sha256: "f82b6e4cc300fb546dc0d741f91c41f1267af7f58386e4bf35007d85ffab235b"
validated_via: [drop-test, ci-smoke]
observation_backend:
ig_version: v0.51.0
gadgets: []
run_config:
user: ""
command: []
entrypoint: ""
network: ""
pid: ""
devices: []
security_opt: ["no-new-privileges:true"]
mounts: []
env: []
drop_test:
checks:
- {removed: /tmp, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}