Summary
Any shell (or child process) spawned by the AppImage inherits a private, unprivileged user namespace created during the FUSE/DwarFS self-mount. Tools that check real uid/capability metadata against on-disk ownership - sudo, and sandboxes built on bubblewrap (e.g. Codex CLI) - fail inside that shell, because root (uid 0) isn't mapped in the namespace.
Reproduction
$ ~/Applications/Ghostty-<version>-x86_64.AppImage
# in the resulting shell:
$ sudo apt update
sudo: /etc/sudo.conf is owned by uid 65534, should be 0
sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit set
Evidence
cat /proc/self/uid_map in the shell: 1000 1000 1 - only uid 1000 is mapped; uid 0 has no mapping, so root-owned files appear as uid 65534 (kernel.overflowuid).
- Compare to
/proc/1/uid_map (init, not namespaced): full range mapped.
readlink /proc/<pid>/ns/user is identical across the dwarfs mount process, the ghostty binary, and the login shell - confirming they share one namespace.
strace -f -e trace=clone,clone3,unshare,setns on the raw AppImage shows the runtime attempting a pidfd-based setns() (namespace reuse across launches); the fully-extracted binary (--appimage-extract then run AppRun directly) makes zero such calls.
/proc/self/status in the shell shows CapEff: 00000000ffffffff - full capabilities despite not being setuid/root, which is what trips bwrap's own sanity check (bwrap: Unexpected capabilities but not setuid, old file caps config?), breaking Codex CLI's sandbox the same way.
Workaround confirmed working
Embedding APPIMAGE_EXTRACT_AND_RUN=1 via --appimage-addenvs avoids the FUSE mount (and thus the namespace) entirely - verified via strace: zero clone/unshare/setns calls, sudo and bwrap both work normally afterward.
Question for you
Given #158 was actually fixed upstream in Anylinux-AppImages rather than here, is this the same situation - i.e. is the unshare/reuse behavior coming from uruntime/quick-sharun rather than anything ghostty-appimage-specific? If so, is baking APPIMAGE_EXTRACT_AND_RUN=1 into the build (or fixing the reuse logic to not require a private namespace) something you'd want done here, upstream, or not at all? Happy to send a PR to bin/bundle-appimage.sh if that's the right place - wanted your read first given the shared-tooling precedent.
Note: written with AI assistance (Claude Code) during a debugging session.
Summary
Any shell (or child process) spawned by the AppImage inherits a private, unprivileged user namespace created during the FUSE/DwarFS self-mount. Tools that check real uid/capability metadata against on-disk ownership -
sudo, and sandboxes built onbubblewrap(e.g. Codex CLI) - fail inside that shell, because root (uid 0) isn't mapped in the namespace.Reproduction
Evidence
cat /proc/self/uid_mapin the shell:1000 1000 1- only uid 1000 is mapped; uid 0 has no mapping, so root-owned files appear as uid 65534 (kernel.overflowuid)./proc/1/uid_map(init, not namespaced): full range mapped.readlink /proc/<pid>/ns/useris identical across thedwarfsmount process, theghosttybinary, and the login shell - confirming they share one namespace.strace -f -e trace=clone,clone3,unshare,setnson the raw AppImage shows the runtime attempting apidfd-basedsetns()(namespace reuse across launches); the fully-extracted binary (--appimage-extractthen runAppRundirectly) makes zero such calls./proc/self/statusin the shell showsCapEff: 00000000ffffffff- full capabilities despite not being setuid/root, which is what tripsbwrap's own sanity check (bwrap: Unexpected capabilities but not setuid, old file caps config?), breaking Codex CLI's sandbox the same way.Workaround confirmed working
Embedding
APPIMAGE_EXTRACT_AND_RUN=1via--appimage-addenvsavoids the FUSE mount (and thus the namespace) entirely - verified viastrace: zeroclone/unshare/setnscalls,sudoandbwrapboth work normally afterward.Question for you
Given #158 was actually fixed upstream in
Anylinux-AppImagesrather than here, is this the same situation - i.e. is the unshare/reuse behavior coming fromuruntime/quick-sharunrather than anything ghostty-appimage-specific? If so, is bakingAPPIMAGE_EXTRACT_AND_RUN=1into the build (or fixing the reuse logic to not require a private namespace) something you'd want done here, upstream, or not at all? Happy to send a PR tobin/bundle-appimage.shif that's the right place - wanted your read first given the shared-tooling precedent.Note: written with AI assistance (Claude Code) during a debugging session.