diff --git a/.github/workflows/container-ci.yml b/.github/workflows/container-ci.yml index 8d4dc10f..accf9a23 100644 --- a/.github/workflows/container-ci.yml +++ b/.github/workflows/container-ci.yml @@ -89,9 +89,9 @@ jobs: - name: Verify bundled scanner run: | - docker run --rm codex-security:ci --version - docker run --rm codex-security:ci bulk-scan --help - docker run --rm codex-security:ci info --json + docker run --rm --cap-drop ALL --security-opt no-new-privileges codex-security:ci --version + docker run --rm --cap-drop ALL --security-opt no-new-privileges codex-security:ci bulk-scan --help + docker run --rm --cap-drop ALL --security-opt no-new-privileges codex-security:ci info --json - name: Validate hardened customer Compose configuration env: @@ -133,7 +133,7 @@ jobs: shell: bash run: | set -euo pipefail - if output="$(docker run --rm -t codex-security:ci bulk-scan 2>&1)"; then + if output="$(docker run --rm -t --cap-drop ALL --security-opt no-new-privileges codex-security:ci bulk-scan 2>&1)"; then echo "The customer container must require a repository CSV." >&2 exit 1 else diff --git a/docker/codex-security-seccomp.json b/docker/codex-security-seccomp.json index 9b281782..dd5f7a73 100644 --- a/docker/codex-security-seccomp.json +++ b/docker/codex-security-seccomp.json @@ -323,7 +323,6 @@ "signalfd4", "sigprocmask", "sigreturn", - "socketcall", "socketpair", "splice", "stat", @@ -378,24 +377,29 @@ "action": "SCMP_ACT_ALLOW" }, { - "names": ["process_vm_readv", "process_vm_writev", "ptrace"], + "names": ["socket"], "action": "SCMP_ACT_ALLOW", - "includes": { "minKernel": "4.8" } + "comment": "AF_UNIX(1)/AF_INET(2)/AF_INET6(10) only: local IPC + HTTPS for git clone and the OpenAI API. Everything else (notably AF_NETLINK=16, AF_PACKET=17) is denied by defaultAction; the previous 3-rule form here only blocked AF_ALG=38/AF_VSOCK=40 and left NETLINK/PACKET/everything-else allowed.", + "args": [{ "index": 0, "value": 1, "op": "SCMP_CMP_EQ" }] }, { "names": ["socket"], "action": "SCMP_ACT_ALLOW", - "args": [{ "index": 0, "value": 38, "op": "SCMP_CMP_LT" }] + "args": [{ "index": 0, "value": 2, "op": "SCMP_CMP_EQ" }] }, { "names": ["socket"], "action": "SCMP_ACT_ALLOW", - "args": [{ "index": 0, "value": 39, "op": "SCMP_CMP_EQ" }] + "args": [{ "index": 0, "value": 10, "op": "SCMP_CMP_EQ" }] }, { "names": ["socket"], "action": "SCMP_ACT_ALLOW", - "args": [{ "index": 0, "value": 40, "op": "SCMP_CMP_GT" }] + "comment": "AF_NETLINK(16) restricted to NETLINK_ROUTE(0): Bubblewrap's Linux sandbox needs a NETLINK_ROUTE socket to run RTM_NEWLINK/RTM_NEWADDR when it configures the loopback interface inside its own (already-isolated) network namespace during codex sandbox startup.", + "args": [ + { "index": 0, "value": 16, "op": "SCMP_CMP_EQ" }, + { "index": 2, "value": 0, "op": "SCMP_CMP_EQ" } + ] }, { "names": ["personality"], diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 4eb56299..a4e79ff8 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -2,6 +2,24 @@ set -eu +# Fail closed instead of silently degrading: docker/codex-security-seccomp.json +# allows mount/pivot_root/unshare/setns/clone unconditionally, on the assumption +# (previously only a comment) that the caller runs this image with +# --cap-drop ALL --security-opt no-new-privileges (as compose.yaml does). If +# someone runs the raw image without that contract, refuse to start rather than +# let the seccomp profile's namespace/mount allowlist apply with capabilities +# or new-privilege escalation still available. +caps=$(awk '/^CapEff:/{print $2}' /proc/self/status 2>/dev/null || true) +if [ "$caps" != "0000000000000000" ]; then + printf '%s\n' "codex-security: refusing to start without --cap-drop ALL (effective capabilities are not empty: ${caps:-unknown})." >&2 + exit 3 +fi +nnp=$(awk '/^NoNewPrivs:/{print $2}' /proc/self/status 2>/dev/null || true) +if [ "$nnp" != "1" ]; then + printf '%s\n' "codex-security: refusing to start without --security-opt no-new-privileges." >&2 + exit 3 +fi + if [ "${1:-}" = bulk-scan ]; then case "${2:-}" in --help|-h)