All guides
Medium severityFile, Path & Resource Handling

Open directory indexes: when your file server lists everything

When directory indexing is enabled, visiting a path like /uploads/ returns a browsable list of every file in that directory instead of a 403 or 404. Attackers look here first because backup archives, log files, and uploaded user content are regularly left world-readable inside web-served directories.

What it is

Directory listing (also called directory indexing) is a web server feature that generates an HTML file browser when a directory is requested and no index file is present. Enabled by default in some nginx configurations (autoindex on) and Apache (Options +Indexes), it's a convenience for static hosts that becomes a liability anywhere files shouldn't be public.

AppSafe checks a set of commonly misconfigured paths — /uploads/, /files/, /backup/, /backups/, /logs/, and /tmp/ — and flags any that return a recognisable directory listing response. Even one open directory can expose data that was never meant to be discoverable.

Why it matters

Exposed directories routinely contain user-uploaded files, compressed database dumps, application logs with credentials or session tokens, and source archives left over from deploys. Finding them requires no authentication and no exploitation — just typing the URL.

Automated scanners probe the same well-known paths AppSafe checks, continuously, against every reachable host. An open /backup/ directory containing a .sql.gz dump is effectively a full database export handed over without a password.

How to fix it

Disable autoindex in nginx

Remove or explicitly turn off the autoindex directive in any server or location block that serves user-controlled directories.

location /uploads/ {
  autoindex off;
  # Serve individual files but never list directory contents
}
Move sensitive directories outside the web root

The safest fix is to store uploads, backups, and logs in a directory the web server doesn't serve at all. Your application reads and streams files through an authenticated route — the raw filesystem path is never reachable.

In Next.js, gate file access behind a route handler

Never put user uploads or backups inside the public/ directory. Serve them through an API route that can enforce authentication and sanitise the requested path.

// app/api/uploads/[filename]/route.ts
import { getSession } from "@/lib/auth-session";
import { readFile } from "fs/promises";
import path from "path";

export async function GET(
  _req: Request,
  { params }: { params: { filename: string } }
) {
  const session = await getSession();
  if (!session) return new Response(null, { status: 401 });

  // path.basename prevents directory traversal
  const safe = path.basename(params.filename);
  const filePath = path.join(process.cwd(), "private-uploads", safe);
  const data = await readFile(filePath);
  return new Response(data);
}
Protect internal listing endpoints with authentication

If you genuinely need a browsable file interface (a media library, an internal log viewer), protect the path with authentication rather than relying on obscurity.

location /logs/ {
  autoindex on;
  auth_basic "Internal only";
  auth_basic_user_file /etc/nginx/.htpasswd;
}

FAQ

Is directory listing always a problem, or only on certain paths?

It's a problem wherever the files contain anything sensitive. A public CDN serving static images with indexing on is usually harmless; /logs/, /backup/, and /uploads/ almost never are, because they accumulate files that weren't vetted for public access.

Can I just drop an empty index.html in the directory to block listing?

That hides the listing for that one directory but leaves every subdirectory open. It's also easy to miss when new directories are created. Turning off autoindex at the server level is a reliable, configuration-level fix that covers everything beneath it.

What severity does AppSafe report for an open directory index?

Medium. The listing itself isn't the compromise — it's the path to one. A browsable /backup/ directory containing a database dump or a /logs/ directory with authentication tokens in plain text quickly escalates beyond medium on its own.

Is your app affected?

AppSafe checks for this and dozens of other issues in one free scan.

Scan my app free