Information
While the system administrator can establish secure permissions for users' "dot"
directories, the users can easily override these. Dot directories are the hidden
subdirectories within a user's home directory (their names begin with a . ) that hold
per-user configuration, state, and credential material. Common examples include:
- .ssh - holds the user's SSH private keys, authorized_keys, known_hosts, and
client configuration. Read or write access by other users can lead to credential theft
or unauthorized authentication.
- .gnupg - holds the user's GnuPG keyring and trust database.
- .config, .local - hold application configuration and per-user data
(XDG base directories).
- .cache - holds cached application data, which can include tokens or session material.
User configuration directories with excessive or incorrect access may enable malicious
users to read, steal, or modify other users' data - or to gain another user's system
privileges. A weakly-permissioned .ssh directory is particularly dangerous: if it is
group- or world-writable, another user can drop an authorized_keys entry and obtain
the victim's identity; if it is readable by others, private key material can be exfiltrated.
Solution
Making global modifications to users' directories without alerting the user community
can result in unexpected outages and unhappy users. Therefore, it is recommended that a
monitoring policy be established to report user dot directory permissions and determine
the action to be taken in accordance with site policy.
The following script will, within local interactive users' home directories:
- remove excessive permissions on dot directories (max 0750 ; .ssh max 0700 )
- change ownership of dot directories to the user
- change group ownership of dot directories to the user's primary group
Note: Like the audit, this remediation scopes its action to local interactive
users' home directories only and does not traverse the entire filesystem.
#!/usr/bin/env bash
{
l_maxsize="1000" # Maximum number of local interactive users before warning (Default 1,000)
l_valid_shells="^($( awk -F\/ '$NF != "nologin" {print}' /etc/shells | sed -rn '/^\//{s,/,\\\\/,g;p}' | paste -s -d '|' - ))$"
a_user_and_home=() # Create array with local users and their home directories
while read -r l_local_user l_local_user_home; do # Populate array with users and user home location
[[ -n "$l_local_user" && -n "$l_local_user_home" ]] && a_user_and_home+=("$l_local_user:$l_local_user_home")
done <<< "$(awk -v pat="$l_valid_shells" -F: '$(NF) ~ pat { print $1 " " $(NF-1) }' /etc/passwd)"
l_asize="${#a_user_and_home[@]}" # Here if we want to look at number of users before proceeding
[ "${#a_user_and_home[@]}" -gt "$l_maxsize" ] && printf '%s\n' "" " ** INFO **" \
" - \"$l_asize\" Local interactive users found on the system" \
" - This may be a long running check" ""
dir_access_fix()
{
l_max="$( printf '%o' $(( 0777 & ~$l_mask)) )"
if [ $(( $l_mode & $l_mask )) -gt 0 ]; then
printf '%s\n' "" " - Directory: \"$l_hddir\" is mode: \"$l_mode\" and should be mode: \"$l_max\" or more restrictive" \
" Updating directory: \"$l_hddir\" to be mode: \"$l_max\" or more restrictive"
chmod "$l_change" "$l_hddir"
fi
if [[ ! "$l_owner" =~ ($l_user) ]]; then
printf '%s\n' "" " - Directory: \"$l_hddir\" owned by: \"$l_owner\" and should be owned by \"${l_user//|/ or }\"" \
" Updating directory: \"$l_hddir\" to be owned by \"${l_user//|/ or }\""
chown "$l_user" "$l_hddir"
fi
if [[ ! "$l_gowner" =~ ($l_group) ]]; then
printf '%s\n' "" " - Directory: \"$l_hddir\" group owned by: \"$l_gowner\" and should be group owned by \"${l_group//|/ or }\"" \
" Updating directory: \"$l_hddir\" to be group owned by \"${l_group//|/ or }\""
chgrp "$l_group" "$l_hddir"
fi
}
while IFS=: read -r l_user l_home; do
# Skip home directories that reside on a network / remote filesystem
l_fstype="$(findmnt -no FSTYPE --target "$l_home" 2>/dev/null)"
case "$l_fstype" in
nfs|nfs4|cifs|smbfs|smb3|fuse.sshfs|afs|ncpfs|glusterfs|ceph)
printf '%s\n' "" " - User: \"$l_user\" Home Directory: \"$l_home\" skipped (remote/network filesystem: $l_fstype)"
continue ;;
esac
if [ -d "$l_home" ]; then
l_group="$(id -gn "$l_user" | xargs)";l_group="${l_group// /|}"
while IFS= read -r -d $'\0' l_hddir; do
while read -r l_mode l_owner l_gowner; do
case "$(basename "$l_hddir")" in
.ssh )
l_mask='0077'; l_change="g-rwx,o-rwx"; dir_access_fix ;;
* )
l_mask='0027'; l_change="g-w,o-rwx"; dir_access_fix ;;
esac
done < <(stat -Lc '%#a %U %G' "$l_hddir")
done < <(find "$l_home" -xdev -type d -name '.*' -print0)
fi
done <<< "$(printf '%s\n' "${a_user_and_home[@]}")"
}
<xhtml:hr />
Note: This recommendation intentionally avoids a full-filesystem traversal
( find / ) when locating dot directories. A system-wide search for . -prefixed
directories is expensive and can take a very long time on hosts with large or networked
filesystems, and it would repeatedly cross into directory trees (caches, build
artifacts, application data) that are not user credential stores. Instead, the audit and
remediation are scoped to the home directories of local interactive users - users
who have a valid login shell as enumerated from /etc/passwd and /etc/shells - and
use find "$l_home" -xdev -type d -name '.*' (the -xdev guard also keeps the scan on
the home filesystem and prevents descent into mounted filesystems). This mirrors the
scope of recommendation 7.2.10.
Limitation of this scope: Dot directories that hold sensitive material but reside
outside local interactive users' home directories - for example, credential or
configuration directories created under /opt, /srv, application working directories,
or the home directories of service/system accounts that use nologin / false shells -
are not evaluated by this automated check. Administrators should ensure, through
separate review or site-specific tooling, that no unexpected dot directories with weak
permissions (group- or world-writable, or readable by other where they hold secrets)
exist outside the audited scope. If your environment stores per-user credentials outside
standard interactive home directories, treat those locations under a separate control.
Impact:
Making global modifications to users' directories without alerting the user community can
result in unexpected outages and unhappy users. Tightening permissions on a dot directory
may break applications that relied on group or world access to per-user state (for
example, a service account configured to read another user's .config ). Establish a
monitoring policy and apply changes in accordance with site policy.
This recommendation intentionally scopes its scan to local interactive users' home
directories only and does not traverse the entire filesystem. As a
result, dot directories that live outside those home directories are out of scope for this
automated check and must be reviewed separately.