Directory Listing and WordPress: Escalating Old School Bug

Introduction

I vividly remember the days when directory listing was regarded as a significant issue during penetration testing engagements. As a penetration tester, another challenge was identifying creative ways to chain vulnerabilities and escalate their severity. However, with directory listing, all we could do was look for backup files, sensitive documents, and similar items. This article is all about escalating directory listing by leveraging the behavior of the WordPress application to achieve something meaningful.

My own professional journey led me to become mid-late adopter of WordPress, back when I first heard about PHP CMS through word of mouth. I still have a deep respect for WordPress because it was open source, easy to use, and experimental specially during that period of time. Plus, this blog also runs on WordPress. Nowadays, despite ongoing criticism, WordPress continues to be a preferred solution for individuals, organizations, and development firms worldwide, and it still maintains a strong market share, according to WPbeginner.

Security vulnerabilities in WordPress were, and still are, widely prevalent due to third-party integrations, user misconfigurations, and outdated libraries or dependencies. The WordPress platform also allows and supports custom plugins and themes, which can certainly introduce major risks. It is still not too late to dive into WordPress security.

Revisiting Directory Listing in WordPress

Now, after several years, I chose to revisit the same basic & classic vulnerability i.e directory listing. This isn’t my first time working with WordPress security. I have previously shared some articles on the topics such as WordPress Misconfiguration to RCE and Denial Of Service(DOS) abusing WordPress Database Repair which I believe are worth exploring.

Throughout my experience, I have occasionally been interested in the concept of vulnerability chaining and maximizing impact by combining seemingly minor misconfigurations. I began to reconsider the relevance of directory listing within the context of WordPress instances. It is well known that, in some cases, websites inadvertently reveal directory structures or expose uploaded files, system logs, and backup files allowing unauthorized users to access or download sensitive data. However, the question remains: can this behavior be further leveraged to exploit the logic inherent to the WordPress application itself if it is vulnerable to directory listing?

Imagine you are working on an important post or page in WordPress that has files uploaded and attached to it. The post or page should not be published before its time and, for now, is saved as a draft. You might assume it is safe simply because it has not been published. However, if the server where your WordPress instance is installed is vulnerable to directory listing, anyone can stumble across the uploaded files and learn about the ongoing tasks you are working on. Because the attachments are not protected by any kind of authentication by default. Directory listing has been regarded as a minor security issue but its impact can be far more significant when combined with the logic of WordPress.

WordPress’s Behaviour

WordPress stores media files using a predictable, upload date-based structure. Supposing that no external CDN is used and webserver is vulnerable to directory listing, all the files uploaded by WordPress users will be visible under /wp-content/uploads/YYYY/MM/.

To explore why this is important, break this into more tangible scenarios by considering the following two cases:

Case I : Drafts and Published Posts

Whenever a WordPress user crafts a post and includes a file, the uploaded file is stored in a directory structure such as wp-content/uploads/YYYY/MM/, where the folder names correspond to the year and month of the upload date. If the post is saved as a draft or discarded, the media file still resides on the server and can be accessed without any authentication. Of course, the upload folder will contain the list of files that are related with published post or draft.

Case II : Direct Uploads

Another case is when a user uploads a file directly in the media library without creating any post because it can be used as a file management or sharing system as well. Assume the usage is like WordPress administrator uploads a file in media library for later to use or just to share the file remotely without refrencing it in the post. These files will be also visible in the wp-content/uploads/YYYY/MM/ directory but will never be seen anywhere in the blog.

From both of the cases, the folder wp-content/uploads/YYYY/MM/ will contain the list of files:

  1. Attached in published posts + Files belonging to draft posts
  2. Uploaded directly in Media manager for Sharing or later use

Attack Methodology: Correlating Directory Listing and WordPress REST API

In a WordPress site where directory listing is enabled, a user can browse to wp-content/uploads/ and recursively enumerate all uploaded files. Additionally, the WP REST API can be used to list all media files associated with published posts.

To find the source of truth for the media files related to the WordPress post or pages, we now have two methods:

  1. WordPress Rest API: With the help of WordPress REST API, we can discover the media files related to published posts, or the files uploaded to the Media Library but not attached to any post.
  2. Directory Listing: By crawling all available directories in /wp-content/uploads/ recursively, we can list all the media files users have uploaded.

By comparing these two data sets, one can identify files that are present on the server but not attached to any published content. Files discovered through directory listing minus files obtained from the WordPress REST API(Files attached to the published posts) equals the leaked or abandoned files. Or, as an equation:

Files from Directory Listing − Files from WP REST API = Abandoned or Private files (Leaks)

Image: Simple logic for finding Abandoned(Orphaned) or Private files

This approach exposes:

  • Files linked to draft posts and not intended for public consumption at least for the moment;
  • Media files uploaded to the server but subsequently forgotten or unused;
  • In effect, potential data leaks involving private or sensitive content.

Exploiting the Issue: WP-STEG Tool

To put this vulnerability into practice, I developed WP-STEG, a lightweight script for uncovering such misconfigurations. WP-STEG automates the discovery of orphaned or private media files. These include images, documents, or PDFs that have been uploaded to the WordPress server but are either linked only to draft posts or never referenced in any published content.

These overlooked files can be a goldmine for attackers, exposing sensitive information that was never meant to go public. For example, private data, internal screenshots, or files uploaded by mistake.

WP-STEG works by:

  • Checking preconditions, ensuring the target is a WordPress installation with directory listing and the REST API enabled.
  • Fetching all media URLs currently referenced by published content via the WordPress REST API, excluding entries with post:null.
  • Recursively crawling the uploads directory for every file actually present on the server.
  • Comparing both lists to highlight files that are still accessible but never made public.

It combines robust crawling, precise WordPress logic, and noise reduction (such as thumbnail and variant normalization) to delivers actionable results. WP-STEG is built to uncover secrets from any WordPress instance which is vulnerable to directory listing.

Image: Working of WP-Steg Tool

You can check out the tool here: WP-STEG on GitHub

If you think WP-STEG can be improved, suggestions and contributions are welcome.

Remediation

By design, WordPress does not require any authentication to access media files. While this is intended to make media sharing simple, it also creates a potential security risk. Combined with common server misconfigurations like directory listing enabled which can expose sensitive or unpublished files to anyone.

If you own a WordPress website, these are some important things to keep in mind to help keep your site secure.

Disable Directory Listing on the Server:
Directory listing allows visitors to see all files in a folder, which is rarely needed and can lead to unintended data exposure. Disabling directory listing on your web server (whether Apache, Nginx, or another) helps prevent attackers from browsing upload folders.

Regularly Audit and Clean Up Your Media Library:
Over time, WordPress sites accumulate orphaned or unused media files especially those attached to draft posts or uploaded directly without association to a published post. Periodic audits and cleanups help remove forgotten files that could pose a privacy risk if exposed.

Harden Your WordPress Installation:
Strengthening your WordPress setup with security best practices and plugins reduces the risk of exploitation. This includes restricting REST API access, enforcing strong authentication, and monitoring for suspicious activity.

Conclusion

It took me some time to see directory listing from this angle, but once I did, the full implications of this vulnerability became clear. Specifically, how directory listing chained with WordPress’s media management logic can expose unpublished or abandoned files that pose significant privacy and security risks. To the best of my knowledge, this perspective has not been extensively explored in existing research or discussions. I welcome any references or insights from others who might have studied this before, and I hope this work encourages further investigation into this important issue.