# Host system files served publicly from customer web root via symlink (FollowSymLinks without SymLinksIfOwnerMatch, incomplete fix for FS#440) ## Summary An SSH or FTP user can place a symlink in their web root pointing at a world-readable file of the host system (outside the account), and the site's Apache vhost serves that file to anyone over HTTPS. No authentication on the visitor side, no special privileges on the account side. I reproduced this with `/etc/passwd`, `/etc/fstab`, `/etc/resolv.conf`, `/etc/hostname` and `/etc/mysql/my.cnf`, served from my own test account. FS#440 was closed as Fixed after `/alwaysdata/etc/passwd` was removed and staff entries were filtered from NSS. The report itself stated that any world-readable system file can be exposed this way, and that is still true: the symlink mechanism was not changed. ## Vulnerable asset - `ssh://ssh-[account].alwaysdata.net` (shell access to the account) - `https://[account].alwaysdata.net/` (the vhost that follows the symlink) - `ftp://ftp-[account].alwaysdata.net` (proftpd offers `SITE SYMLINK`, see below) ## Root cause 1. The per-account Apache configuration (`/home/[account]/admin/config/apache/apache.conf`, readable inside the account) sets `Options ExecCGI FollowSymLinks` and never sets `SymLinksIfOwnerMatch`. Apache therefore follows symlinks to targets owned by other users, including root. 2. proftpd still offers `SITE SYMLINK source destination` to customer sessions (visible in `SITE HELP`), so symlinks can be created without SSH at all. 3. Host files that are world-readable (`/etc/passwd`, `/etc/fstab`, `/etc/resolv.conf`, `/etc/mysql/my.cnf`, ...) are reachable from the customer session's filesystem view. FS#440 removed `/alwaysdata/etc/passwd`, but the mechanism works with any remaining world-readable host file. The exposure boundary is exactly the host's file permissions: a symlink to `/etc/shadow` returns 403 because Apache's user cannot read it, while anything world-readable is served. ## Steps to reproduce All steps on my own account only (zhamhmd), free plan. Tested 2026-09-04. 1. Create the symlink: ``` $ ssh zhamhmd@ssh-zhamhmd.alwaysdata.net $ ln -sf /etc/passwd ~/www/bbt_fresh ``` 2. Fetch it from outside, without any authentication: ``` $ curl -s -o /dev/null -w "%{http_code} %{size_download}\n" https://zhamhmd.alwaysdata.net/bbt_fresh 200 1764 $ curl -s https://zhamhmd.alwaysdata.net/bbt_fresh | head -4 root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin ``` That is the host's `/etc/passwd`: 34 system accounts, including `www-data`. My own account (uid 544975, zhamhmd) does not appear in it, which shows the served file belongs to the host namespace, not the account namespace. 3. Controls: ``` $ curl -s -o /dev/null -w "%{http_code}\n" https://zhamhmd.alwaysdata.net/bbt_NOEXIST 404 $ ln -sf /etc/shadow ~/www/bbt_shadow $ curl -s -o /dev/null -w "%{http_code}\n" https://zhamhmd.alwaysdata.net/bbt_shadow 403 ``` 4. Other world-readable host files served the same way, all HTTP 200: - `/etc/fstab`, which shows `/home` is a network-mounted xfs volume with `grpquota` and `_netdev`, and `/proc` is mounted with `hidepid=2` - `/proc/mounts` - `/etc/resolv.conf` - `/etc/hostname` - `/etc/mysql/my.cnf` 5. Files with restrictive permissions are correctly refused: `/etc/shadow`, `/etc/mysql/debian.cnf`, `/etc/mysql/mariadb.conf.d/50-server.cnf`, `/var/log/auth.log`, `/proc/net/tcp`, `/etc/ssh/sshd_config`. 6. FTP-only variant: `SITE SYMLINK` is listed in `SITE HELP` on `ftp-[account].alwaysdata.net`. The FTP jail sees less of the filesystem than SSH, so `/etc/*` is not reachable from it today, but the command is available to customers and the Apache side behaves the same. All symlinks were removed after each test and nothing beyond the public system files listed above was accessed. ## Impact - Every account can publish host system files on its public website, and any visitor can read them. This fits the program's "Exposure of configuration files or secrets" and "Local File Disclosure" categories. - The affected set is not a fixed list of files. Any world-readable file on the host, including files added by future package updates, becomes publishable by any customer. Fixing FS#440 by deleting one file does not bound the problem. - What I confirmed is not affected: files with restrictive permissions (403), staff account disclosure from FS#426 (the NSS filter still holds, and the host `/etc/passwd` contains no staff entries), and no access to other customers' data. ## Why this is not covered by FS#440 FS#440 was closed as Fixed on 10.08.2026. Its own report stated: "Any world-readable system file can be exposed this way (/etc/passwd, /etc/mysql/mariadb.cnf, etc.)". The fix removed the staff file and filtered NSS, but did not change the Apache symlink behavior or proftpd's SITE command set, and the suggested fix in FS#440 ("Set /alwaysdata/etc/passwd and /alwaysdata/etc/group to mode 640 root:alwaysdata_team") was about a file that no longer exists. The mechanism described there still works today against host files, which is what this report demonstrates with fresh reproduction steps. ## Suggested fix 1. Add `SymLinksIfOwnerMatch` to the per-account vhost template (or drop `FollowSymLinks`). Symlinks then only resolve when the target is owned by the account user. This is the usual shared-hosting setting and does not break normal sites. 2. Remove `SYMLINK` from proftpd's SITE command set for customer accounts. 3. Optionally re-check world-readable permissions on host directories reachable from customer sessions, as suggested in FS#440. Option 1 by itself would have prevented FS#440 and this report. ## References - FS#440: Incomplete Fix for FS#426 - Staff Files Still Publicly Accessible via Symlink (closed Fixed 10.08.2026) - FS#426: Internal staff account and privilege hierarchy disclosure via SSH (closed Fixed 04.08.2026) - https://httpd.apache.org/docs/2.4/mod/core.html#symlinksifownermatch