write only sandbox doesn't work inside a container

Open 💬 3 comments Opened May 20, 2026 by purpleidea
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of Codex CLI is running?

codex-cli 0.131.0

What subscription do you have?

pro

Which model were you using?

gpt-5.5

What platform is your computer?

Fedora Linux 43

What terminal emulator and version are you using (if applicable)?

bash

Codex doctor report

What issue are you seeing?

I'm running codex to try and avoid annoying approvals for writes in the workspace:

codex --sandbox workspace-write --ask-for-approval untrusted

If I ask it to write a TEST file I see:

Would you like to make the following edits? Reason: command failed; retry without sandbox?

And if I do yes, codex often writes python scripts that just write to files. This is completely insane and is wasting a ton of tokens.

I'm running codex inside of a podman container, so I suspect the nested bwrap is conflicting. I do NOT want to run privileged because I don't want to give codex more perms. I do want it to write normally as if I had disabled the inner sandbox. I don't want to disable the sandbox for anything other than file writes.

What steps can reproduce the bug?

Open codex cli inside a podman container by running: codex --sandbox workspace-write --ask-for-approval untrusted. Ask it to write a TEST file.

What is the expected behavior?

It should just work without a sandbox error. It should ask me for permission though if I've set to untrusted.

Additional information

NOTE: This used to work just fine, but broke in some recent update within the last 2 months or less I believe.

View original on GitHub ↗

3 Comments

github-actions[bot] contributor · 3 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #23468

Powered by Codex Action

purpleidea · 3 months ago

Related but not a dupe if you look at the specifics I mention in terms of what the user should expect to see happen.

purpleidea · 2 months ago

Codex security and design really is... something. I'm running the entirely of codex inside my own bwrap container because I don't trust it. But as mentioned in this issue, when codex tries to spawn a child bwrap to accomplish a task, this fails! I'm not going to give the root-like privs to allow nested bwrap, that would defeat the point.

But if you disable needing bwrap with codex --sandbox danger-full-access this also disables the yes/no "do I want to accept this edit" prompts, which I do want so I can easily say no and guide codex back on track!

So what did I do today? I asked codex to create a shim bwrap which just passes things through... It was able to do this without needing any special perms. It added to ~/.npm-global/bin/bwrap the below script.

It didn't need any special perms to do so. And now I run codex --sandbox read-only --ask-for-approval on-request and things work as expected.

Should be a good example of why codex security is fake nonsense AFAICT.

HTH

PS: As a side note, I've noticed pretty serious degradation in ability within the last two weeks... Something weird is going on and my personal research seems to indicate that openai (maybe at the request of the U.S. government) have deliberately "nerfed" the model. GPT5.5 pro.

XXX: codex built this to deal with the nested bwrap buggy garbage

#!/usr/bin/env bash
set -euo pipefail

real_bwrap=/usr/bin/bwrap

case "${1-}" in
	--help|--version)
		exec "$real_bwrap" "$@"
		;;
esac

argv0=""
clearenv=false
chdir=""
setenv_args=()
unsetenv_args=()

need_args() {
	local opt=$1
	local need=$2
	local have=$(($# - 2))
	if ((have < need)); then
		printf 'bwrap-noop: %s needs %d argument(s)\n' "$opt" "$need" >&2
		exit 125
	fi
}

while (($#)); do
	case "$1" in
		--)
			shift
			break
			;;
		--argv0)
			need_args "$1" 1 "$@"
			argv0=$2
			shift 2
			;;
		--chdir)
			need_args "$1" 1 "$@"
			chdir=$2
			shift 2
			;;
		--clearenv)
			clearenv=true
			shift
			;;
		--setenv)
			need_args "$1" 2 "$@"
			setenv_args+=("$2=$3")
			shift 3
			;;
		--unsetenv)
			need_args "$1" 1 "$@"
			unsetenv_args+=("$2")
			shift 2
			;;
		--level-prefix|--unshare-all|--share-net|--unshare-user|--unshare-user-try|--unshare-ipc|--unshare-pid|--unshare-net|--unshare-uts|--unshare-cgroup|--unshare-cgroup-try|--disable-userns|--assert-userns-disabled|--new-session|--die-with-parent|--as-pid-1)
			shift
			;;
		--args)
			printf 'bwrap-noop: --args is not supported by this shim\n' >&2
			exit 125
			;;
		--userns|--userns2|--pidns|--uid|--gid|--hostname|--lock-file|--sync-fd|--remount-ro|--overlay-src|--tmp-overlay|--ro-overlay|--exec-label|--file-label|--proc|--dev|--tmpfs|--mqueue|--dir|--seccomp|--add-seccomp-fd|--block-fd|--userns-block-fd|--info-fd|--json-status-fd|--cap-add|--cap-drop|--perms|--size)
			need_args "$1" 1 "$@"
			shift 2
			;;
		--bind|--bind-try|--dev-bind|--dev-bind-try|--ro-bind|--ro-bind-try|--bind-fd|--ro-bind-fd|--file|--bind-data|--ro-bind-data|--symlink|--chmod)
			need_args "$1" 2 "$@"
			shift 3
			;;
		--overlay)
			need_args "$1" 3 "$@"
			shift 4
			;;
		--*=*)
			printf 'bwrap-noop: unsupported option form: %s\n' "$1" >&2
			exit 125
			;;
		-*)
			printf 'bwrap-noop: unsupported option: %s\n' "$1" >&2
			exit 125
			;;
		*)
			break
			;;
	esac
done

if (($# == 0)); then
	printf 'bwrap-noop: missing command\n' >&2
	exit 125
fi

if [[ -n "$chdir" ]]; then
	cd "$chdir"
fi

if "$clearenv"; then
	if [[ -n "$argv0" ]]; then
		printf 'bwrap-noop: --argv0 with --clearenv is not supported by this shim\n' >&2
		exit 125
	fi
	exec env -i "${setenv_args[@]}" "$@"
fi

for name in "${unsetenv_args[@]}"; do
	unset "$name"
done
for pair in "${setenv_args[@]}"; do
	export "$pair"
done

if [[ -n "$argv0" ]]; then
	exec -a "$argv0" "$@"
fi

exec "$@"