Keep Require all denied on the root directory
apache2.conf / httpd.conf<Directory /> Options None AllowOverride None Require all denied</Directory>
<Directory /var/www/html> Options -Indexes +FollowSymLinks AllowOverride None Require all granted</Directory>This is Apache’s shipped default. On most servers the correct action here is to put it back.
Why it matters
Section titled “Why it matters”The <Directory /> block sets the policy for the filesystem root, and Apache
applies directory sections from shortest path to longest — so / is the base that
everything else overrides.
Denying at / and granting back at /var/www/html means the default answer for
any path Apache is asked about is no. A path bug, an Alias typo, a rewrite
mistake, a symlink pointing somewhere unexpected — all of them hit a wall, because
nothing outside your document root was ever permitted.
Reverse it, and every one of those becomes file disclosure.
This is not hypothetical
Section titled “This is not hypothetical”In October 2021, Apache 2.4.49 shipped a path normalisation change that allowed
.. sequences through URL decoding — CVE-2021-41773. The fix in 2.4.50 missed
double URL encoding, so CVE-2021-42013 followed days later. Both were
exploited in the wild within hours of disclosure.
The detail that matters here: both required a non-default configuration. The
traversal only reached files that Apache was willing to serve, and a server with
the default Require all denied on <Directory /> was not willing to serve
anything outside its document root. Servers that had swapped it for
Require all granted had their /etc/passwd read — and with
mod_cgi loaded, had commands executed.
So the population that got hit was, specifically, the people who had removed a default they didn’t understand.
Full details are on the path traversal page.
Why people remove it
Section titled “Why people remove it”The same way trust gets into pg_hba.conf:
something returns 403, and this makes it stop.
<Directory /> Require all granted # don't</Directory>The real fix is almost always a <Directory> block for the specific path you
wanted to serve. If content lives outside /var/www, grant that directory — not
the root of the filesystem.
Options None in the root block matters too: it means no Indexes, no
ExecCGI, and no FollowSymLinks by default. Symlink following at / is its own
route out of the document root.
Related
Section titled “Related”- The Apache path traversal — what this default prevented.
- Disable unused modules — mod_cgi is what turned it into RCE.