From a84f05d41bef76561f5dd0881614bd6f4a0b45ff Mon Sep 17 00:00:00 2001 From: Josh Knapp Date: Tue, 20 Oct 2026 15:52:01 -0700 Subject: [PATCH] fix(entrypoint): unlink planted symlinks as the customer, never as root Same race-safety as cac: drop_symlink and the logs/ symlink sweep run as the customer, so a parent dir swapped for a symlink between check and rm cannot redirect a root unlink. Co-Authored-By: Claude Opus 5.5 --- scripts/entrypoint.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh index ad382ca..c05cc5a 100755 --- a/scripts/entrypoint.sh +++ b/scripts/entrypoint.sh @@ -31,10 +31,12 @@ as_user() { runuser -u "$user" -- "$@" fi } +# Unlink AS THE CUSTOMER, so a parent dir swapped for a symlink between the +# check and the rm can only reach what the customer could already. drop_symlink() { if [ -L "$1" ]; then - echo "entrypoint: SECURITY: $1 was a symlink to '$(readlink "$1")' - removed" >&2 - rm -f -- "$1" + echo "entrypoint: SECURITY: $1 was a symlink to '$(readlink "$1")' - removing" >&2 + as_user rm -f -- "$1" || echo "entrypoint: WARNING: could not remove symlink $1" >&2 fi } if [ -L /home/$user ] || [ ! -d /home/$user ]; then @@ -45,9 +47,11 @@ chown -h $user:$user /home/$user # app/ may legitimately be a symlink (releases/current deploys): it is left # alone, and every root-side operation on it below runs as the customer. drop_symlink /home/$user/logs -if [ -d /home/$user/logs ]; then - # nginx opens its logs here as root; find without -L never follows links. - find /home/$user/logs -xdev -type l -print0 2>/dev/null | while IFS= read -r -d '' l; do drop_symlink "$l"; done +if [ -d /home/$user/logs ] && [ ! -L /home/$user/logs ]; then + # nginx opens its logs here as root. As the customer, find without -L never + # follows symlinks; -delete unlinks them. + as_user find /home/$user/logs -xdev -type l \ + -printf 'entrypoint: SECURITY: %p was a symlink to %l - removed\n' -delete >&2 || true fi as_user mkdir -p /home/$user/app /home/$user/logs/nginx /home/$user/logs/nodejs