Silent NFS Export Leaks on Home NAS
Running a lightweight NFS server on a Raspberry Pi or a small Ubuntu Server is a common way to share media or backups.
The problem? A mis‑configured export table can let a client mount a directory that was never meant to be exposed. The server happily replies “yes”, so the admin might not notice until a log entry pops up or a backup job starts to fail.
Below is a hands‑on walk‑through that shows how to spot and patch those leaks on a Debian‑based NAS. The same ideas apply to other distros; just swap package names and service names.
1. Inspect the Export Table
# Show the current export rules
cat /etc/exports
Typical entries look like:
/srv/nfs/media 192.168.1.0/24(rw,sync,no_subtree_check)
A silent leak usually shows up when you use a wildcard, an overly permissive subnet, or accidentally export a directory you didn’t mean to.
# Verify that every exported path actually exists
while read -r line; do
path=$(echo "$line" | awk '{print $1}')
[ -d "$path" ] || echo "Missing: $path"
done < /etc/exports
If you see a “Missing” line, the export is dangling and will still accept mounts until you restart the server.
2. Check Active Mounts
# List all mounts that came from the local NFS server
mount | grep "$(hostname -I | awk '{print $1}')"
Or, on the server side:
# Show all NFS clients currently attached
exportfs -v
The output lists each client IP, the exported path, and the options used.
If you spot a client that shouldn’t have access, that’s your leak.
3. Audit Client‑Side Mounts
On a client, run:
mount | grep nfs
Look for mounts that reference your NAS IP but point to a directory you didn’t intend to share.
If you’re using autofs, check /etc/auto.master and the corresponding map files.
4. Tighten the Export Rules
- Remove wildcards – replace
*or/with explicit subnets or hostnames. - Use
root_squash– prevents root on the client from becoming root on the server. - Add
no_subtree_checkonly when necessary – it can hide a missing directory if the parent is exported.
Example:
# /etc/exports
/srv/nfs/media 192.168.1.100/32(rw,sync,no_subtree_check,root_squash)
After editing, reload:
sudo exportfs -ra
5. Harden the NFS Daemon
-
Disable NFSv2 – it’s obsolete and has known bugs.
# /etc/nfs.conf [nfsd] nfsvers=3,4.2 -
Enable
sec=sysorsec=krb5if you need stronger authentication.
sec=sysis the default;krb5requires Kerberos setup. -
Limit the number of NFS threads to reduce the attack surface:
# /etc/systemd/system/nfs-server.service.d/override.conf [Service] ExecStart= ExecStart=/usr/sbin/rpc.nfsd 8(8 threads is enough for most home setups.)
6. Monitor for Unauthorized Mounts
Create a simple audit rule:
sudo auditctl -w /etc/exports -p wa -k nfs_export_changes
And a cron job to check exportfs -v against a whitelist:
#!/usr/bin/env bash
whitelist=$(cat /etc/nfs_whitelist)
current=$(exportfs -v | awk '{print $2}')
diff=$(comm -23 <(echo "$current" | sort) <(echo "$whitelist" | sort))
[ -n "$diff" ] && echo "Unauthorized mounts: $diff" | mail -s "NFS Leak Alert" [email protected]
Store the whitelist as a simple list of allowed client IPs.
7. Test the Fix
From a client that previously had access, try to mount a non‑exported directory:
sudo mount -t nfs 192.168.1.10:/srv/nfs/secret /mnt/secret
You should receive:
mount.nfs: access denied by server while mounting 192.168.1.10:/srv/nfs/secret
If the mount succeeds, double‑check the export list and reload.
8. Keep the Server Updated
NFS bugs are rare but still happen. Apply kernel and NFS package updates promptly:
sudo apt update && sudo apt full-upgrade
Check the kernel changelog for NFS fixes:
9. Optional: Use nfs4-acl for Fine‑Grained Control
If you need per‑user permissions, switch to NFSv4 and enable ACLs:
# /etc/exports
/srv/nfs/media 192.168.1.0/24(rw,sync,no_subtree_check,fsid=0)
Then set ACLs with setfacl:
setfacl -m u:alice:rwx /srv/nfs/media
NFSv4 ACLs are more secure but require client support.
10. Summary of Trade‑offs
| Approach | Pros | Cons |
|---|---|---|
| Explicit IPs | Least privilege | Needs update when clients change |
root_squash |
Prevents privilege escalation | Some apps need root access |
| NFSv4 ACLs | Fine‑grained | More complex, client support |
| Disable NFSv2 | Removes legacy bugs | No backward compatibility |
Pick the mix that fits your homelab’s size and trust model.
See also
- How to Stop Docker‑Compatible Containers from Writing Sensitive Files to the Host with Rootless Mode
- Configuring systemd‑resolved to Use a Custom DNS Server Only on the VPN Interface
- Recovering from emergency mode after a bad /etc/fstab entry on Ubuntu 24.04: a single‑command root shell solution
- How to Give the Backup User Read‑Only Access to /var/log via ACLs Without Granting sudo
- Rootless Podman on a Raspberry Pi – Solving the “Cannot Bind Mount /home/user/data” Permission Issue