diff --git a/RECIPE-API-CHANGELOG.md b/RECIPE-API-CHANGELOG.md
index c5962969..d0aa6e1a 100644
--- a/RECIPE-API-CHANGELOG.md
+++ b/RECIPE-API-CHANGELOG.md
@@ -1061,3 +1061,19 @@ incorrect build results.
 
 Changes in next
 ---------------
+
+### Execution of privileged commands
+
+When operations require higher privileges than those available to the build user,
+the following helper functions shall be used:
+
+**run_privileged**: Run a command as root while preserving the environment.
+
+**run_privileged_heredoc**: Execute commands provided via stdin in a root shell.
+
+**run_in_chroot**: Run a command within a chroot environment. The first argument
+specifies the rootfs path.
+
+Using these helpers instead of direct `sudo` invocations centralizes platform-specific
+privileged execution logic in `base.bbclass`. Direct use of `sudo` is discouraged
+in downstream layers.
diff --git a/meta/classes-global/base.bbclass b/meta/classes-global/base.bbclass
index 70b4565b..d4dbbc3a 100644
--- a/meta/classes-global/base.bbclass
+++ b/meta/classes-global/base.bbclass
@@ -141,7 +141,7 @@ root_cleandirs() {
             die "Could not remove $i, because subdir is mounted"
     done
     for i in $ROOT_CLEANDIRS_DIRS; do
-        sudo rm -rf --one-file-system "$TMPDIR$i"
+        run_privileged rm -rf --one-file-system "$TMPDIR$i"
         mkdir -p "$TMPDIR$i"
     done
 }
@@ -375,3 +375,27 @@ def deb_list_beautify(d, varname):
         if stripped:
             var_list.append(stripped)
     return ', '.join(var_list)
+
+# Helpers for privileged execution. Only the non-underscore functions
+# shall be used outside of this class.
+
+def run_privileged_cmd(d):
+    cmd = 'sudo -E'
+    bb.debug(1, "privileged cmd: %s" % cmd)
+    return cmd
+
+RUN_PRIVILEGED_CMD := "${@run_privileged_cmd(d)}"
+
+run_privileged() {
+    ${RUN_PRIVILEGED_CMD} "$@"
+}
+
+run_privileged_heredoc() {
+    ${RUN_PRIVILEGED_CMD} /bin/bash -s "$@"
+}
+
+run_in_chroot() {
+    rootfs="$1"
+    shift
+    ${RUN_PRIVILEGED_CMD} chroot "$rootfs" "$@"
+}
diff --git a/meta/classes-recipe/deb-dl-dir.bbclass b/meta/classes-recipe/deb-dl-dir.bbclass
index e3f055c5..04fd6414 100644
--- a/meta/classes-recipe/deb-dl-dir.bbclass
+++ b/meta/classes-recipe/deb-dl-dir.bbclass
@@ -98,7 +98,7 @@ debsrc_download() {
 dbg_pkgs_download() {
     export rootfs="$1"
 
-    apt-ftparchive --md5=no --sha1=no --sha256=no --sha512=no \
+    dbg_pkgs=$(apt-ftparchive --md5=no --sha1=no --sha256=no --sha512=no \
                    -a "${DISTRO_ARCH}" packages \
                    "${rootfs}/var/cache/apt/archives" \
     | awk '/^Package:/ {print $2}' \
@@ -110,7 +110,9 @@ dbg_pkgs_download() {
             | grep "${DISTRO_ARCH}" \
             | awk '!/Binary:/ {print $1}' \
             | sort -u
-    done | xargs -r sudo -E chroot ${rootfs} sh -c '/usr/bin/apt-get -y --download-only install "$@"' --
+    done)
+
+    [ -z "${dbg_pkgs}" ] || run_in_chroot ${rootfs} sh -c '/usr/bin/apt-get -y --download-only install $@' -- ${dbg_pkgs}
 }
 
 deb_dl_dir_import() {
@@ -120,7 +122,7 @@ deb_dl_dir_import() {
     export gid=$(id -g)
 
     # let our unprivileged user place downloaded packages in /var/cache/apt/archives/
-    sudo -Es << '    EOSUDO'
+    run_privileged_heredoc << '    EOSUDO'
         mkdir -p "${rootfs}"/var/cache/apt/archives/partial/
         chown -R ${uid}:${gid} "${rootfs}"/var/cache/apt/archives/
     EOSUDO
diff --git a/meta/classes-recipe/dpkg-base.bbclass b/meta/classes-recipe/dpkg-base.bbclass
index f7a12302..e5987554 100644
--- a/meta/classes-recipe/dpkg-base.bbclass
+++ b/meta/classes-recipe/dpkg-base.bbclass
@@ -161,7 +161,7 @@ def isar_export_build_settings(d):
 
 dpkg_schroot_create_configs() {
     schroot_create_configs
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
         sbuild_fstab="${SBUILD_CONF_DIR}/fstab"
         fstab_isarapt="${WORKDIR}/isar-apt/${DISTRO}-${DISTRO_ARCH}/apt/${DISTRO} /isar-apt none rw,bind 0 0"
         grep -qxF "${fstab_isarapt}" ${sbuild_fstab} || echo "${fstab_isarapt}" >> ${sbuild_fstab}
diff --git a/meta/classes-recipe/dpkg.bbclass b/meta/classes-recipe/dpkg.bbclass
index c1c38184..dcdef487 100644
--- a/meta/classes-recipe/dpkg.bbclass
+++ b/meta/classes-recipe/dpkg.bbclass
@@ -129,5 +129,5 @@ dpkg_runbuild() {
     deb_dl_dir_export "${WORKDIR}/rootfs" "${distro}"
 
     # Cleanup apt artifacts
-    sudo rm -rf ${WORKDIR}/rootfs
+    run_privileged rm -rf ${WORKDIR}/rootfs
 }
diff --git a/meta/classes-recipe/image-account-extension.bbclass b/meta/classes-recipe/image-account-extension.bbclass
index e874f3c7..de01484c 100644
--- a/meta/classes-recipe/image-account-extension.bbclass
+++ b/meta/classes-recipe/image-account-extension.bbclass
@@ -34,7 +34,7 @@ def image_create_groups(d: "DataSmart") -> None:
     """
     entries = (d.getVar("GROUPS") or "").split()
     rootfsdir = d.getVar("ROOTFSDIR")
-    chroot = ["sudo", "-E", "chroot", rootfsdir]
+    chroot = run_privileged_cmd(d).split() + ["chroot", rootfsdir]
 
     for entry in entries:
         args = []
@@ -72,7 +72,7 @@ def image_create_users(d: "DataSmart") -> None:
 
     entries = (d.getVar("USERS") or "").split()
     rootfsdir = d.getVar("ROOTFSDIR")
-    chroot = ["sudo", "-E", "chroot", rootfsdir]
+    chroot = run_privileged_cmd(d).split() + ["chroot", rootfsdir]
 
     for entry in entries:
         args = []
diff --git a/meta/classes-recipe/image-locales-extension.bbclass b/meta/classes-recipe/image-locales-extension.bbclass
index c90280aa..029caec7 100644
--- a/meta/classes-recipe/image-locales-extension.bbclass
+++ b/meta/classes-recipe/image-locales-extension.bbclass
@@ -29,7 +29,7 @@ ROOTFS_INSTALL_COMMAND_BEFORE_EXPORT += "image_install_localepurge_download"
 image_install_localepurge_download[weight] = "40"
 image_install_localepurge_download[network] = "${TASK_USE_NETWORK_AND_SUDO}"
 image_install_localepurge_download() {
-    sudo -E chroot '${ROOTFSDIR}' \
+    run_in_chroot '${ROOTFSDIR}' \
         /usr/bin/apt-get ${ROOTFS_APT_ARGS} -oDebug::NoLocking=1 --download-only localepurge
 }
 
@@ -60,7 +60,7 @@ ${@get_nopurge(d)}
 __EOF__
 
     # Install configuration into image:
-    sudo -E -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
         set -e
         localepurge_state='i'
         if chroot '${ROOTFSDIR}' dpkg -s localepurge 2>/dev/null >&2
diff --git a/meta/classes-recipe/image-postproc-extension.bbclass b/meta/classes-recipe/image-postproc-extension.bbclass
index 43ab750c..59128c2a 100644
--- a/meta/classes-recipe/image-postproc-extension.bbclass
+++ b/meta/classes-recipe/image-postproc-extension.bbclass
@@ -17,19 +17,19 @@ update_etc_os_release() {
     done
 
     if [ -n "${OS_RELEASE_BUILD_ID}" ]; then
-        sudo sed -i '/^BUILD_ID=.*/d' '${IMAGE_ROOTFS}/etc/os-release'
+        run_privileged sed -i '/^BUILD_ID=.*/d' '${IMAGE_ROOTFS}/etc/os-release'
         echo "BUILD_ID=\"${OS_RELEASE_BUILD_ID}\"" | \
-            sudo tee -a '${IMAGE_ROOTFS}/etc/os-release'
+            run_privileged tee -a '${IMAGE_ROOTFS}/etc/os-release'
     fi
     if [ -n "${OS_RELEASE_VARIANT}" ]; then
-        sudo sed -i '/^VARIANT=.*/d' '${IMAGE_ROOTFS}/etc/os-release'
+        run_privileged sed -i '/^VARIANT=.*/d' '${IMAGE_ROOTFS}/etc/os-release'
         echo "VARIANT=\"${OS_RELEASE_VARIANT}\"" | \
-            sudo tee -a '${IMAGE_ROOTFS}/etc/os-release'
+            run_privileged tee -a '${IMAGE_ROOTFS}/etc/os-release'
     fi
     if [ -n "${OS_RELEASE_VARIANT_VERSION}" ]; then
-        sudo sed -i '/^VARIANT_VERSION=.*/d' '${IMAGE_ROOTFS}/etc/os-release'
+        run_privileged sed -i '/^VARIANT_VERSION=.*/d' '${IMAGE_ROOTFS}/etc/os-release'
         echo "VARIANT_VERSION=\"${OS_RELEASE_VARIANT_VERSION}\"" | \
-            sudo tee -a '${IMAGE_ROOTFS}/etc/os-release'
+            run_privileged tee -a '${IMAGE_ROOTFS}/etc/os-release'
     fi
 }
 
@@ -37,11 +37,11 @@ ROOTFS_POSTPROCESS_COMMAND =+ "image_postprocess_configure"
 image_postprocess_configure() {
     # Configure root filesystem
     if [ -n "${DISTRO_CONFIG_SCRIPT}" ]; then
-        sudo install -m 755 "${WORKDIR}/${DISTRO_CONFIG_SCRIPT}" "${IMAGE_ROOTFS}"
+        run_privileged install -m 755 "${WORKDIR}/${DISTRO_CONFIG_SCRIPT}" "${IMAGE_ROOTFS}"
         TARGET_DISTRO_CONFIG_SCRIPT="$(basename ${DISTRO_CONFIG_SCRIPT})"
-        sudo chroot ${IMAGE_ROOTFS} "/$TARGET_DISTRO_CONFIG_SCRIPT" \
+        run_in_chroot ${IMAGE_ROOTFS} "/$TARGET_DISTRO_CONFIG_SCRIPT" \
                                     "${MACHINE_SERIAL}" "${BAUDRATE_TTY}"
-        sudo rm "${IMAGE_ROOTFS}/$TARGET_DISTRO_CONFIG_SCRIPT"
+        run_privileged rm "${IMAGE_ROOTFS}/$TARGET_DISTRO_CONFIG_SCRIPT"
    fi
 }
 
@@ -58,13 +58,13 @@ image_postprocess_machine_id() {
     # systemd(1) takes care of recreating the machine-id on first boot
     # for systemd < v247, set to empty string, else set to uninitialized
     # (required if initramfs with ro root is used)
-    SYSTEMD_VERSION=$( sudo chroot ${IMAGE_ROOTFS} dpkg-query --showformat='${source:Upstream-Version}' --show systemd || echo "0" )
+    SYSTEMD_VERSION=$( run_in_chroot ${IMAGE_ROOTFS} dpkg-query --showformat='${source:Upstream-Version}' --show systemd || echo "0" )
     MACHINE_ID="uninitialized"
     if dpkg --compare-versions "$SYSTEMD_VERSION" "lt" "247"; then
         MACHINE_ID=""
     fi
-    echo "$MACHINE_ID" | sudo chroot ${IMAGE_ROOTFS} tee /etc/machine-id
-    sudo rm -f '${IMAGE_ROOTFS}/var/lib/dbus/machine-id'
+    echo "$MACHINE_ID" | run_in_chroot ${IMAGE_ROOTFS} tee /etc/machine-id
+    run_privileged rm -f '${IMAGE_ROOTFS}/var/lib/dbus/machine-id'
 }
 
 ROOTFS_POSTPROCESS_COMMAND =+ "image_postprocess_sshd_key_regen"
@@ -82,13 +82,13 @@ image_postprocess_sshd_key_regen() {
 
 ROOTFS_POSTPROCESS_COMMAND =+ "image_postprocess_disable_systemd_firstboot"
 image_postprocess_disable_systemd_firstboot() {
-    SYSTEMD_VERSION=$(sudo chroot '${ROOTFSDIR}' dpkg-query \
+    SYSTEMD_VERSION=$(run_in_chroot '${ROOTFSDIR}' dpkg-query \
         --showformat='${source:Upstream-Version}' \
         --show systemd || echo "0" )
 
     if dpkg --compare-versions "$SYSTEMD_VERSION" "ge" "251"; then
-        sudo chroot '${ROOTFSDIR}' systemctl mask systemd-firstboot
-        if ! cmd_output=$(sudo chroot '${ROOTFSDIR}' systemd-firstboot \
+        run_in_chroot '${ROOTFSDIR}' systemctl mask systemd-firstboot
+        if ! cmd_output=$(run_in_chroot '${ROOTFSDIR}' systemd-firstboot \
                --prompt --welcome=false </dev/null 2>/dev/null); then
             bbwarn "Your image is not configured completely according to systemd-firstboot."
             bbwarn "It prompted: \"${cmd_output}\""
diff --git a/meta/classes-recipe/image.bbclass b/meta/classes-recipe/image.bbclass
index 866df68a..9fcdda48 100644
--- a/meta/classes-recipe/image.bbclass
+++ b/meta/classes-recipe/image.bbclass
@@ -364,7 +364,7 @@ get_build_id() {
 ROOTFS_CONFIGURE_COMMAND += "image_configure_fstab"
 image_configure_fstab[weight] = "2"
 image_configure_fstab() {
-    sudo tee '${IMAGE_ROOTFS}/etc/fstab' << EOF
+    run_privileged tee '${IMAGE_ROOTFS}/etc/fstab' << EOF
 # Begin /etc/fstab
 proc		/proc		proc		nosuid,noexec,nodev	0	0
 sysfs		/sys		sysfs		nosuid,noexec,nodev	0	0
@@ -392,7 +392,7 @@ do_copy_boot_files() {
         kernel="$(realpath -q '${IMAGE_ROOTFS}'/boot/vmlinu[xz])"
     fi
     if [ -f "$kernel" ]; then
-        sudo cat "$kernel" > "${DEPLOYDIR}/${KERNEL_IMAGE}"
+        run_privileged cat "$kernel" > "${DEPLOYDIR}/${KERNEL_IMAGE}"
     fi
 
     for file in ${DTB_FILES}; do
@@ -448,7 +448,7 @@ def apt_list_files(d):
 IMAGE_LISTS = "${@ ' '.join(apt_list_files(d)) }"
 
 do_rootfs_finalize() {
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
         set -e
 
         if [ -e "${ROOTFSDIR}/chroot-setup.sh" ]; then
@@ -474,14 +474,14 @@ EOSUDO
 
     # Sometimes qemu-user-static generates coredumps in chroot, move them
     # to work temporary directory and inform user about it.
-    for f in $(sudo find ${ROOTFSDIR} -type f -name *.core -exec file --mime-type {} \; | grep 'application/x-coredump' | cut -d: -f1); do
-        sudo mv "${f}" "${WORKDIR}/temp/"
+    for f in $(run_privileged find ${ROOTFSDIR} -type f -name *.core -exec file --mime-type {} \; | grep 'application/x-coredump' | cut -d: -f1); do
+        run_privileged mv "${f}" "${WORKDIR}/temp/"
         bbwarn "found core dump in rootfs, check it in ${WORKDIR}/temp/${f##*/}"
     done
 
     # Set same time-stamps to the newly generated file/folders in the
     # rootfs image for the purpose of reproducible builds.
-    sudo find ${ROOTFSDIR} -newermt "$(date -d@${SOURCE_DATE_EPOCH} '+%Y-%m-%d %H:%M:%S')" \
+    run_privileged find ${ROOTFSDIR} -newermt "$(date -d@${SOURCE_DATE_EPOCH} '+%Y-%m-%d %H:%M:%S')" \
         -exec touch '{}' -h -d@${SOURCE_DATE_EPOCH} ';'
 }
 do_rootfs_finalize[network] = "${TASK_USE_SUDO}"
@@ -518,7 +518,7 @@ do_rootfs_quality_check() {
             ;;
 	esac
     done
-    found=$( sudo find ${ROOTFSDIR} -type f -newer $rootfs_install_stamp $args )
+    found=$( run_privileged find ${ROOTFSDIR} -type f -newer $rootfs_install_stamp $args )
     if [ -n "$found" ]; then
         bbwarn "Files changed after package install. The following files seem"
 	bbwarn "to have changed where they probably should not have."
diff --git a/meta/classes-recipe/imagetypes_container.bbclass b/meta/classes-recipe/imagetypes_container.bbclass
index fba15503..fb1d0cdf 100644
--- a/meta/classes-recipe/imagetypes_container.bbclass
+++ b/meta/classes-recipe/imagetypes_container.bbclass
@@ -37,38 +37,38 @@ do_containerize() {
 
     # prepare OCI container image skeleton
     bbdebug 1 "prepare OCI container image skeleton"
-    sudo rm -rf "${oci_img_dir}" "${oci_img_dir}_unpacked"
-    sudo umoci init --layout "${oci_img_dir}"
-    sudo umoci new --image "${oci_img_dir}:${empty_tag}"
+    run_privileged rm -rf "${oci_img_dir}" "${oci_img_dir}_unpacked"
+    run_privileged umoci init --layout "${oci_img_dir}"
+    run_privileged umoci new --image "${oci_img_dir}:${empty_tag}"
     if [ -n "${cmd}" ]; then
-        sudo umoci config --image "${oci_img_dir}:${empty_tag}" \
+        run_privileged umoci config --image "${oci_img_dir}:${empty_tag}" \
             --config.cmd="${cmd}"
     fi
     if [ -n "${entrypoint}" ]; then
-        sudo umoci config --image "${oci_img_dir}:${empty_tag}" \
+        run_privileged umoci config --image "${oci_img_dir}:${empty_tag}" \
             --config.entrypoint="${entrypoint}"
     fi
     if [ -n "${path}" ]; then
-        sudo umoci config --image "${oci_img_dir}:${empty_tag}" \
+        run_privileged umoci config --image "${oci_img_dir}:${empty_tag}" \
             --config.env="PATH=${path}"
     fi
-    sudo umoci unpack --image "${oci_img_dir}:${empty_tag}" \
+    run_privileged umoci unpack --image "${oci_img_dir}:${empty_tag}" \
         "${oci_img_dir}_unpacked"
 
     # add root filesystem as the flesh of the skeleton
-    sudo cp --reflink=auto -a "${rootfs}"/* "${oci_img_dir}_unpacked/rootfs/"
+    run_privileged cp --reflink=auto -a "${rootfs}"/* "${oci_img_dir}_unpacked/rootfs/"
     # clean-up temporary files
-    sudo find "${oci_img_dir}_unpacked/rootfs/tmp" -mindepth 1 -delete
+    run_privileged find "${oci_img_dir}_unpacked/rootfs/tmp" -mindepth 1 -delete
 
     # pack container image
     bbdebug 1 "pack container image"
-    sudo umoci repack --image "${oci_img_dir}:${tag}" \
+    run_privileged umoci repack --image "${oci_img_dir}:${tag}" \
         "${oci_img_dir}_unpacked"
-    sudo umoci remove --image "${oci_img_dir}:${empty_tag}"
-    sudo rm -rf "${oci_img_dir}_unpacked"
+    run_privileged umoci remove --image "${oci_img_dir}:${empty_tag}"
+    run_privileged rm -rf "${oci_img_dir}_unpacked"
 
     # no root needed anymore
-    sudo chown --recursive $(id -u):$(id -g) "${oci_img_dir}"
+    run_privileged chown --recursive $(id -u):$(id -g) "${oci_img_dir}"
 }
 
 convert_container() {
diff --git a/meta/classes-recipe/imagetypes_wic.bbclass b/meta/classes-recipe/imagetypes_wic.bbclass
index dd6c501d..8b048dc7 100644
--- a/meta/classes-recipe/imagetypes_wic.bbclass
+++ b/meta/classes-recipe/imagetypes_wic.bbclass
@@ -193,8 +193,8 @@ generate_wic_image() {
         fi
 EOIMAGER
 
-    sudo chown -R $(stat -c "%U" ${LAYERDIR_core}) ${LAYERDIR_core} ${LAYERDIR_isar} ${SCRIPTSDIR} || true
-    sudo chown -R $(id -u):$(id -g) "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic"*
+    run_privileged chown -R $(stat -c "%U" ${LAYERDIR_core}) ${LAYERDIR_core} ${LAYERDIR_isar} ${SCRIPTSDIR} || true
+    run_privileged chown -R $(id -u):$(id -g) "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic"*
     rm -rf ${IMAGE_ROOTFS}/../pseudo
 
     cat ${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.manifest \
diff --git a/meta/classes-recipe/rootfs.bbclass b/meta/classes-recipe/rootfs.bbclass
index b201b97d..440786b5 100644
--- a/meta/classes-recipe/rootfs.bbclass
+++ b/meta/classes-recipe/rootfs.bbclass
@@ -136,7 +136,7 @@ rootfs_cmd() {
 
 rootfs_do_mounts[weight] = "3"
 rootfs_do_mounts() {
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
         set -e
         mountpoint -q '${ROOTFSDIR}/dev' || \
             ( mount -o bind,private /dev '${ROOTFSDIR}/dev' &&
@@ -182,7 +182,7 @@ EOSUDO
 }
 
 rootfs_do_umounts() {
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
         set -e
         if mountpoint -q '${ROOTFSDIR}/isar-apt'; then
             umount '${ROOTFSDIR}/isar-apt'
@@ -225,7 +225,7 @@ rootfs_do_qemu() {
     if [ '${@repr(d.getVar('ROOTFS_ARCH') == d.getVar('HOST_ARCH'))}' = 'False' ]
     then
         test -e '${ROOTFSDIR}/usr/bin/qemu-${QEMU_ARCH}-static' || \
-            sudo cp '/usr/bin/qemu-${QEMU_ARCH}-static' '${ROOTFSDIR}/usr/bin/qemu-${QEMU_ARCH}-static'
+            run_privileged cp '/usr/bin/qemu-${QEMU_ARCH}-static' '${ROOTFSDIR}/usr/bin/qemu-${QEMU_ARCH}-static'
     fi
 }
 
@@ -240,16 +240,16 @@ ROOTFS_EXTRA_IMPORTED := "${@rootfs_extra_import(d)}"
 
 rootfs_prepare[weight] = "25"
 rootfs_prepare(){
-    sudo tar -xf "${BOOTSTRAP_SRC}" -C "${ROOTFSDIR}" --exclude="./dev/console"
+    run_privileged tar -xf "${BOOTSTRAP_SRC}" -C "${ROOTFSDIR}" --exclude="./dev/console"
 
     # setup chroot
-    sudo "${ROOTFSDIR}/chroot-setup.sh" "setup" "${ROOTFSDIR}"
+    run_privileged "${ROOTFSDIR}/chroot-setup.sh" "setup" "${ROOTFSDIR}"
 }
 
 ROOTFS_CONFIGURE_COMMAND += "rootfs_configure_isar_apt"
 rootfs_configure_isar_apt[weight] = "2"
 rootfs_configure_isar_apt() {
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
     set -e
 
     mkdir -p '${ROOTFSDIR}/etc/apt/sources.list.d'
@@ -270,7 +270,7 @@ EOSUDO
 ROOTFS_CONFIGURE_COMMAND += "rootfs_configure_apt"
 rootfs_configure_apt[weight] = "2"
 rootfs_configure_apt() {
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
     set -e
 
     mkdir -p '${ROOTFSDIR}/etc/apt/apt.conf.d'
@@ -293,7 +293,7 @@ ROOTFS_CONFIGURE_COMMAND += "rootfs_disable_initrd_generation"
 rootfs_disable_initrd_generation[weight] = "1"
 rootfs_disable_initrd_generation() {
     # fully disable initrd generation
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
     set -e
 
     mkdir -p "${ROOTFSDIR}${ROOTFS_STUBS_DIR}"
@@ -310,7 +310,7 @@ rootfs_install_pkgs_update[weight] = "5"
 rootfs_install_pkgs_update[isar-apt-lock] = "acquire-before"
 rootfs_install_pkgs_update[network] = "${TASK_USE_NETWORK_AND_SUDO}"
 rootfs_install_pkgs_update() {
-    sudo -E chroot '${ROOTFSDIR}' /usr/bin/apt-get update \
+    run_in_chroot '${ROOTFSDIR}' /usr/bin/apt-get update \
         -o Dir::Etc::SourceList="sources.list.d/isar-apt.list" \
         -o Dir::Etc::SourceParts="-" \
         -o APT::Get::List-Cleanup="0"
@@ -322,9 +322,9 @@ rootfs_install_resolvconf() {
     if [ "${@repr(bb.utils.to_boolean(d.getVar('BB_NO_NETWORK')))}" != "True" ]
     then
         if [ -L "${ROOTFSDIR}/etc/resolv.conf" ]; then
-            sudo unlink "${ROOTFSDIR}/etc/resolv.conf"
+            run_privileged unlink "${ROOTFSDIR}/etc/resolv.conf"
         fi
-        sudo cp -rL /etc/resolv.conf '${ROOTFSDIR}/etc'
+        run_privileged cp -rL /etc/resolv.conf '${ROOTFSDIR}/etc'
     fi
 }
 
@@ -358,7 +358,7 @@ rootfs_export_package_cache() {
 ROOTFS_INSTALL_COMMAND += "${@ 'rootfs_install_clean_files' if (d.getVar('ROOTFS_CLEAN_FILES') or '').strip() else ''}"
 rootfs_install_clean_files[weight] = "2"
 rootfs_install_clean_files() {
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
     for clean_file in ${ROOTFS_CLEAN_FILES}; do
         rm -f "${ROOTFSDIR}/$clean_file"
     done
@@ -370,14 +370,14 @@ rootfs_install_pkgs_install[weight] = "8000"
 rootfs_install_pkgs_install[progress] = "custom:rootfs_progress.PkgsInstallProgressHandler"
 rootfs_install_pkgs_install[network] = "${TASK_USE_SUDO}"
 rootfs_install_pkgs_install() {
-    sudo -E chroot "${ROOTFSDIR}" \
+    run_in_chroot "${ROOTFSDIR}" \
         /usr/bin/apt-get ${ROOTFS_APT_ARGS} ${ROOTFS_PACKAGES}
 }
 
 ROOTFS_INSTALL_COMMAND += "rootfs_restore_initrd_tooling"
 rootfs_restore_initrd_tooling[weight] = "1"
 rootfs_restore_initrd_tooling() {
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
     set -e
     rm -f "${ROOTFSDIR}/etc/apt/apt.conf.d/50isar-stubs"
     rm -rf "${ROOTFSDIR}${ROOTFS_STUBS_DIR}"
@@ -386,8 +386,8 @@ EOSUDO
 
 ROOTFS_INSTALL_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'generate-initrd', '', 'rootfs_clear_initrd_symlinks', d)}"
 rootfs_clear_initrd_symlinks() {
-    sudo rm -f ${ROOTFSDIR}/initrd.img
-    sudo rm -f ${ROOTFSDIR}/initrd.img.old
+    run_privileged rm -f ${ROOTFSDIR}/initrd.img
+    run_privileged rm -f ${ROOTFSDIR}/initrd.img.old
 }
 
 do_rootfs_install[root_cleandirs] = "${ROOTFSDIR}"
@@ -437,21 +437,21 @@ do_cache_deb_src[network] = "${TASK_USE_SUDO}"
 do_cache_deb_src() {
     if [ -e "${ROOTFSDIR}"/etc/resolv.conf ] ||
        [ -h "${ROOTFSDIR}"/etc/resolv.conf ]; then
-        sudo mv "${ROOTFSDIR}"/etc/resolv.conf "${ROOTFSDIR}"/etc/resolv.conf.isar
+        run_privileged mv "${ROOTFSDIR}"/etc/resolv.conf "${ROOTFSDIR}"/etc/resolv.conf.isar
     fi
     rootfs_install_resolvconf
     # Note: Isar updates the apt state information(apt-get update) only once during bootstrap and
     # relies on that through out the build. Copy that state information instead of apt-get update
     # which generates a new state from upstream.
-    sudo tar -xf "${BOOTSTRAP_SRC}" ./var/lib/apt/lists --one-top-level="${ROOTFSDIR}"
+    run_privileged tar -xf "${BOOTSTRAP_SRC}" ./var/lib/apt/lists --one-top-level="${ROOTFSDIR}"
 
     deb_dl_dir_import ${ROOTFSDIR} ${ROOTFS_BASE_DISTRO}-${BASE_DISTRO_CODENAME}
     debsrc_download ${ROOTFSDIR} ${ROOTFS_BASE_DISTRO}-${BASE_DISTRO_CODENAME}
 
-    sudo rm -f "${ROOTFSDIR}"/etc/resolv.conf
+    run_privileged rm -f "${ROOTFSDIR}"/etc/resolv.conf
     if [ -e "${ROOTFSDIR}"/etc/resolv.conf.isar ] ||
        [ -h "${ROOTFSDIR}"/etc/resolv.conf.isar ]; then
-        sudo mv "${ROOTFSDIR}"/etc/resolv.conf.isar "${ROOTFSDIR}"/etc/resolv.conf
+        run_privileged mv "${ROOTFSDIR}"/etc/resolv.conf.isar "${ROOTFSDIR}"/etc/resolv.conf
     fi
 }
 
@@ -459,21 +459,21 @@ ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('BASE_REPO_FEATURES', 'cache
 cache_dbg_pkgs() {
     if [ -e "${ROOTFSDIR}"/etc/resolv.conf ] ||
        [ -h "${ROOTFSDIR}"/etc/resolv.conf ]; then
-        sudo mv "${ROOTFSDIR}"/etc/resolv.conf "${ROOTFSDIR}"/etc/resolv.conf.isar
+        run_privileged mv "${ROOTFSDIR}"/etc/resolv.conf "${ROOTFSDIR}"/etc/resolv.conf.isar
     fi
     rootfs_install_resolvconf
     # Note: Isar updates the apt state information(apt-get update) only once during bootstrap and
     # relies on that through out the build. Copy that state information instead of apt-get update
     # which generates a new state from upstream.
-    sudo tar -xf "${BOOTSTRAP_SRC}" ./var/lib/apt/lists --one-top-level="${ROOTFSDIR}"
+    run_privileged tar -xf "${BOOTSTRAP_SRC}" ./var/lib/apt/lists --one-top-level="${ROOTFSDIR}"
 
     deb_dl_dir_import ${ROOTFSDIR} ${ROOTFS_BASE_DISTRO}-${BASE_DISTRO_CODENAME}
     dbg_pkgs_download ${ROOTFSDIR}
 
-    sudo rm -f "${ROOTFSDIR}"/etc/resolv.conf
+    run_privileged rm -f "${ROOTFSDIR}"/etc/resolv.conf
     if [ -e "${ROOTFSDIR}"/etc/resolv.conf.isar ] ||
        [ -h "${ROOTFSDIR}"/etc/resolv.conf.isar ]; then
-        sudo mv "${ROOTFSDIR}"/etc/resolv.conf.isar "${ROOTFSDIR}"/etc/resolv.conf
+        run_privileged mv "${ROOTFSDIR}"/etc/resolv.conf.isar "${ROOTFSDIR}"/etc/resolv.conf
     fi
 }
 
@@ -482,17 +482,17 @@ ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'generate
 
 ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'clean-package-cache', 'rootfs_postprocess_clean_package_cache', '', d)}"
 rootfs_postprocess_clean_package_cache() {
-    sudo -E chroot '${ROOTFSDIR}' \
+    run_in_chroot '${ROOTFSDIR}' \
         /usr/bin/apt-get clean
-    sudo rm -rf "${ROOTFSDIR}/var/lib/apt/lists/"*
+    run_privileged rm -rf "${ROOTFSDIR}/var/lib/apt/lists/"*
     # remove apt-cache folder itself (required in case rootfs is provided by sstate cache)
-    sudo rm -rf "${ROOTFSDIR}/var/cache/apt/archives"
+    run_privileged rm -rf "${ROOTFSDIR}/var/cache/apt/archives"
 }
 
 ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'clean-log-files', 'rootfs_postprocess_clean_log_files', '', d)}"
 rootfs_postprocess_clean_log_files() {
     # Delete log files that are not owned by packages
-    sudo -E chroot '${ROOTFSDIR}' \
+    run_in_chroot '${ROOTFSDIR}' \
         /usr/bin/find /var/log/ -type f \
         -exec sh -c '! dpkg -S {} > /dev/null 2>&1' ';' \
         -exec rm -f {} ';'
@@ -501,32 +501,32 @@ rootfs_postprocess_clean_log_files() {
 ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'clean-debconf-cache', 'rootfs_postprocess_clean_debconf_cache', '', d)}"
 rootfs_postprocess_clean_debconf_cache() {
     # Delete debconf cache files
-    sudo rm -rf "${ROOTFSDIR}/var/cache/debconf/"*
+    run_privileged rm -rf "${ROOTFSDIR}/var/cache/debconf/"*
 }
 
 ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'clean-pycache', 'rootfs_postprocess_clean_pycache', '', d)}"
 rootfs_postprocess_clean_pycache() {
-    sudo find ${ROOTFSDIR}/usr -type f -name '*.pyc'       -delete -print
-    sudo find ${ROOTFSDIR}/usr -type d -name '__pycache__' -delete -print
+    run_privileged find ${ROOTFSDIR}/usr -type f -name '*.pyc'       -delete -print
+    run_privileged find ${ROOTFSDIR}/usr -type d -name '__pycache__' -delete -print
 }
 
 ROOTFS_POSTPROCESS_COMMAND += "rootfs_postprocess_clean_ldconfig_cache"
 rootfs_postprocess_clean_ldconfig_cache() {
     # the ldconfig aux-cache is not portable and breaks reproducability
     # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=845034#49
-    sudo rm -f ${ROOTFSDIR}/var/cache/ldconfig/aux-cache
+    run_privileged rm -f ${ROOTFSDIR}/var/cache/ldconfig/aux-cache
 }
 
 ROOTFS_POSTPROCESS_COMMAND += "rootfs_postprocess_clean_tmp"
 rootfs_postprocess_clean_tmp() {
     # /tmp is by definition non persistent across boots
-    sudo rm -rf "${ROOTFSDIR}/tmp/"*
+    run_privileged rm -rf "${ROOTFSDIR}/tmp/"*
 }
 
 ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'generate-manifest', 'rootfs_generate_manifest', '', d)}"
 rootfs_generate_manifest () {
     mkdir -p ${ROOTFS_MANIFEST_DEPLOY_DIR}
-    sudo -E chroot --userspec=$(id -u):$(id -g) '${ROOTFSDIR}' \
+    run_in_chroot '${ROOTFSDIR}' \
         dpkg-query -W -f \
             '${source:Package}|${source:Version}|${Package}:${Architecture}|${Version}\n' > \
         '${ROOTFS_MANIFEST_DEPLOY_DIR}'/'${ROOTFS_PACKAGE_SUFFIX}'.manifest
@@ -542,7 +542,7 @@ rootfs_export_dpkg_status() {
 ROOTFS_POSTPROCESS_COMMAND += "rootfs_cleanup_isar_apt"
 rootfs_cleanup_isar_apt[weight] = "2"
 rootfs_cleanup_isar_apt() {
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
         set -e
         rm -f "${ROOTFSDIR}/etc/apt/sources.list.d/isar-apt.list"
         rm -f "${ROOTFSDIR}/etc/apt/preferences.d/isar-apt"
@@ -553,7 +553,7 @@ EOSUDO
 ROOTFS_POSTPROCESS_COMMAND += "${@'rootfs_cleanup_base_apt' if bb.utils.to_boolean(d.getVar('ISAR_USE_CACHED_BASE_REPO')) else ''}"
 rootfs_cleanup_base_apt[weight] = "2"
 rootfs_cleanup_base_apt() {
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
         set -e
         rm -f "${ROOTFSDIR}/etc/apt/sources.list.d/"*base-apt.list
 EOSUDO
@@ -561,12 +561,12 @@ EOSUDO
 
 ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'populate-systemd-preset', 'image_postprocess_populate_systemd_preset', '', d)}"
 image_postprocess_populate_systemd_preset() {
-    SYSTEMD_INSTALLED=$(sudo chroot '${ROOTFSDIR}' dpkg-query \
+    SYSTEMD_INSTALLED=$(run_in_chroot '${ROOTFSDIR}' dpkg-query \
         --showformat='${db:Status-Status}' \
         --show systemd || echo "" )
 
     if (test "$SYSTEMD_INSTALLED" = "installed"); then
-        sudo chroot '${ROOTFSDIR}' systemctl preset-all --preset-mode="enable-only"
+        run_in_chroot '${ROOTFSDIR}' systemctl preset-all --preset-mode="enable-only"
     fi
 }
 
@@ -626,7 +626,7 @@ rootfs_generate_initramfs() {
             mods_total="$(find ${ROOTFSDIR}/usr/lib/modules/$kernel_version -type f -name '*.ko*' | wc -l)"
             echo "Total number of modules: $mods_total"
             echo "Generating initrd for kernel version: $kernel_version"
-            sudo -E chroot "${ROOTFSDIR}" sh -ec ' \
+            run_in_chroot "${ROOTFSDIR}" sh -ec ' \
                 ${ROOTFS_INITRAMFS_GENERATOR_CMDLINE}; \
                 find /boot -name "initrd.img-$kernel_version*" -exec install --mode 0644 {} /isar-work/initrd.img \; \
                 '
@@ -664,11 +664,12 @@ rootfs_install_sstate_prepare() {
     # so we use some mount magic to prevent that
     mkdir -p ${WORKDIR}/mnt/rootfs
     trap 'rmdir ${WORKDIR}/mnt/rootfs ${WORKDIR}/mnt' EXIT
-    sudo mount -o bind,private '${WORKDIR}/rootfs' '${WORKDIR}/mnt/rootfs' -o ro
+
+    run_privileged mount -o bind,private '${WORKDIR}/rootfs' '${WORKDIR}/mnt/rootfs' -o ro
     lopts="--one-file-system --exclude=var/cache/apt/archives"
-    sudo tar -C ${WORKDIR}/mnt -cpSf rootfs.tar $lopts ${SSTATE_TAR_ATTR_FLAGS} rootfs
-    sudo umount ${WORKDIR}/mnt/rootfs
-    sudo chown $(id -u):$(id -g) rootfs.tar
+    run_privileged tar -C ${WORKDIR}/mnt -cpSf rootfs.tar $lopts ${SSTATE_TAR_ATTR_FLAGS} rootfs
+    run_privileged umount ${WORKDIR}/mnt/rootfs
+    run_privileged chown $(id -u):$(id -g) rootfs.tar
 }
 do_rootfs_install_sstate_prepare[lockfiles] = "${REPO_ISAR_DIR}/isar.lock"
 
@@ -677,7 +678,7 @@ rootfs_install_sstate_finalize() {
     # - after building the rootfs, the tar won't be there, but we also don't need to unpack
     # - after restoring from cache, there will be a tar which we unpack and then delete
     if [ -f rootfs.tar ]; then
-        sudo tar -C ${WORKDIR} -xpf rootfs.tar ${SSTATE_TAR_ATTR_FLAGS}
+        run_privileged tar -C ${WORKDIR} -xpf rootfs.tar ${SSTATE_TAR_ATTR_FLAGS}
         rm rootfs.tar
     fi
 }
diff --git a/meta/classes-recipe/sbuild.bbclass b/meta/classes-recipe/sbuild.bbclass
index 95dadee3..d9ccce7f 100644
--- a/meta/classes-recipe/sbuild.bbclass
+++ b/meta/classes-recipe/sbuild.bbclass
@@ -20,7 +20,7 @@ SCHROOT_LOCKFILE = "/tmp/schroot.lock"
 schroot_create_configs() {
     mkdir -p "${TMPDIR}/schroot-overlay"
     echo "Creating ${SCHROOT_CONF_FILE}"
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
         set -e
 
         cat << EOF > "${SCHROOT_CONF_FILE}"
@@ -59,7 +59,7 @@ EOSUDO
 schroot_delete_configs() {
     (flock -x 9
     set -e
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
         set -e
         if [ -d "${SBUILD_CONF_DIR}" ]; then
             echo "Removing ${SBUILD_CONF_DIR}"
@@ -101,7 +101,7 @@ sbuild_export() {
 }
 
 insert_mounts() {
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
         set -e
         for mp in ${SCHROOT_MOUNTS}; do
             FSTAB_LINE="${mp%%:*} ${mp#*:} none rw,bind,private 0 0"
@@ -112,7 +112,7 @@ EOSUDO
 }
 
 remove_mounts() {
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
         set -e
         for mp in ${SCHROOT_MOUNTS}; do
             FSTAB_LINE="${mp%%:*} ${mp#*:} none rw,bind,private 0 0"
@@ -123,7 +123,7 @@ EOSUDO
 
 schroot_configure_ccache() {
     mkdir -p "${CCACHE_DIR}"
-    sudo -s <<'EOSUDO'
+    run_privileged_heredoc <<'EOSUDO'
         set -e
 
         sbuild_fstab="${SBUILD_CONF_DIR}/fstab"
diff --git a/meta/classes-recipe/sdk.bbclass b/meta/classes-recipe/sdk.bbclass
index 6f09b5f6..16165792 100644
--- a/meta/classes-recipe/sdk.bbclass
+++ b/meta/classes-recipe/sdk.bbclass
@@ -69,12 +69,12 @@ ROOTFS_POSTPROCESS_COMMAND:remove = "${@'rootfs_cleanup_isar_apt' if bb.utils.to
 ROOTFS_CONFIGURE_COMMAND:append:class-sdk = " ${@'rootfs_configure_isar_apt_dir' if bb.utils.to_boolean(d.getVar('SDK_INCLUDE_ISAR_APT')) else ''}"
 rootfs_configure_isar_apt_dir() {
     # Copy isar-apt instead of mounting:
-    sudo cp -Trpfx --reflink=auto ${REPO_ISAR_DIR}/${DISTRO} ${ROOTFSDIR}/isar-apt
+    run_privileged cp -Trpfx --reflink=auto ${REPO_ISAR_DIR}/${DISTRO} ${ROOTFSDIR}/isar-apt
 }
 
 ROOTFS_POSTPROCESS_COMMAND:prepend:class-sdk = "sdkchroot_configscript "
 sdkchroot_configscript () {
-    sudo chroot ${ROOTFSDIR} /configscript.sh ${DISTRO_ARCH}
+    run_in_chroot ${ROOTFSDIR} /configscript.sh ${DISTRO_ARCH}
 }
 
 ROOTFS_POSTPROCESS_COMMAND:append:class-sdk = " sdkchroot_finalize"
@@ -83,7 +83,7 @@ sdkchroot_finalize() {
     rootfs_do_umounts
 
     # Remove setup scripts
-    sudo rm -f ${ROOTFSDIR}/chroot-setup.sh ${ROOTFSDIR}/configscript.sh
+    run_privileged rm -f ${ROOTFSDIR}/chroot-setup.sh ${ROOTFSDIR}/configscript.sh
 
     # Make all links relative
     for link in $(find ${ROOTFSDIR}/ -type l); do
@@ -95,16 +95,16 @@ sdkchroot_finalize() {
             new_target=$(realpath --no-symlinks -m --relative-to=$basedir ${ROOTFSDIR}${target})
 
             # remove first to allow rewriting directory links
-            sudo rm $link
-            sudo ln -s $new_target $link
+            run_privileged rm $link
+            run_privileged ln -s $new_target $link
         fi
     done
 
     # Set up sysroot wrapper
     for tool_pattern in "gcc-[0-9]*" "g++-[0-9]*" "cpp-[0-9]*" "ld.bfd" "ld.gold"; do
         for tool in $(find ${ROOTFSDIR}/usr/bin -type f -name "*-linux-gnu*-${tool_pattern}"); do
-            sudo mv "${tool}" "${tool}.bin"
-            sudo ln -sf gcc-sysroot-wrapper.sh ${tool}
+            run_privileged mv "${tool}" "${tool}.bin"
+            run_privileged ln -sf gcc-sysroot-wrapper.sh ${tool}
         done
     done
 }
diff --git a/meta/classes/sbom.bbclass b/meta/classes/sbom.bbclass
index b220f3d9..b4fcddaa 100644
--- a/meta/classes/sbom.bbclass
+++ b/meta/classes/sbom.bbclass
@@ -41,7 +41,7 @@ def sbom_doc_uuid(d):
         d.setVar("SBOM_DOCUMENT_UUID", generate_document_uuid(d))
 
 generate_sbom() {
-    sudo mkdir -p ${SBOM_CHROOT}/mnt/rootfs ${SBOM_CHROOT}/mnt/deploy-dir
+    run_privileged mkdir -p ${SBOM_CHROOT}/mnt/rootfs ${SBOM_CHROOT}/mnt/deploy-dir
 
     TIMESTAMP=$(date --iso-8601=s -d @${SOURCE_DATE_EPOCH})
     bwrap \
diff --git a/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc b/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
index f21a6164..da8bc52d 100644
--- a/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
+++ b/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
@@ -209,19 +209,19 @@ do_bootstrap() {
     trap '[ -r "${WORKDIR}/mmtmpdir" ] && tmpdir=$(cat "${WORKDIR}/mmtmpdir") \
                                        && rm "${WORKDIR}/mmtmpdir"; \
           [ -d "$tmpdir" ] && mountpoint -q $tmpdir/$base_apt_tmp \
-                           && sudo umount $tmpdir/$base_apt_tmp; \
+                           && run_privileged umount $tmpdir/$base_apt_tmp; \
           [ -d "$tmpdir" ] && mountpoint -q $tmpdir/base-apt \
-                           && sudo umount $tmpdir/base-apt; \
-          [ -d "$tmpdir" ] && sudo rm -rf --one-file-system $tmpdir; \
+                           && run_privileged umount $tmpdir/base-apt; \
+          [ -d "$tmpdir" ] && run_privileged rm -rf --one-file-system $tmpdir; \
           [ -n "$base_apt_tmp" ] && mountpoint -q $base_apt_tmp \
-                                 && sudo umount $base_apt_tmp \
+                                 && run_privileged umount $base_apt_tmp \
                                  && rm -rf --one-file-system $base_apt_tmp' EXIT
 
     # Create lock file so that it is owned by the user running the build (not root)
     mkdir -p ${DEBDIR}
     touch ${DEB_DL_LOCK}
 
-    sudo TMPDIR="${BOOTSTRAP_TMPDIR}" mmdebstrap $bootstrap_args \
+    run_privileged TMPDIR="${BOOTSTRAP_TMPDIR}" mmdebstrap $bootstrap_args \
                    $arch_param \
                    --mode=unshare \
                    ${MMHOOKS} \
@@ -254,7 +254,7 @@ do_bootstrap() {
 
     if [ "${ISAR_USE_CACHED_BASE_REPO}" != "1" ]; then
         deb_dl_dir_export "${WORKDIR}/dl_dir" "${BOOTSTRAP_BASE_DISTRO}-${BASE_DISTRO_CODENAME}"
-        sudo rm -rf --one-file-system "${WORKDIR}/dl_dir"
+        run_privileged rm -rf --one-file-system "${WORKDIR}/dl_dir"
     fi
 }
 addtask bootstrap before do_build after do_generate_keyrings
diff --git a/testsuite/unittests/test_image_account_extension.py b/testsuite/unittests/test_image_account_extension.py
index f78aa7f8..ff0e47e0 100644
--- a/testsuite/unittests/test_image_account_extension.py
+++ b/testsuite/unittests/test_image_account_extension.py
@@ -54,9 +54,8 @@ class TestImageAccountExtensionImageCreateUsers(
             image_create_users(d)
 
         run_mock.assert_called_once_with(
+            run_privileged_cmd(d).split() +
             [
-                'sudo',
-                '-E',
                 'chroot',
                 rootfs.path(),
                 '/usr/sbin/useradd',
@@ -136,9 +135,8 @@ class TestImageAccountExtensionImageCreateGroups(
             image_create_groups(d)
 
         run_mock.assert_called_once_with(
+            run_privileged_cmd(d).split() +
             [
-                'sudo',
-                '-E',
                 'chroot',
                 rootfs.path(),
                 '/usr/sbin/groupadd',
@@ -164,9 +162,8 @@ class TestImageAccountExtensionImageCreateGroups(
             image_create_groups(d)
 
         run_mock.assert_called_once_with(
+            run_privileged_cmd(d).split() +
             [
-                'sudo',
-                '-E',
                 'chroot',
                 rootfs.path(),
                 '/usr/sbin/groupmod',
