Unauthenticated Disclosure of Unpublished / Embargoed

Disclosed by
0xPewPew
Summary by 0xPewPew

The /wp-json/nasa-external-content/v1/unpublished-posts endpoint on www.nasa.gov is a custom WordPress REST route that returns the full inventory of unpublished/draft content on the site with no authentication and no parameters required. This is a Broken Access Control / IDOR issue: the route was registered without a permission_callback, so WordPress serves data intended only for authenticated editorial staff to any anonymous visitor.

A single unauthenticated GET request returns a JSON object listing every currently unpublished item, grouped by content type, each with its internal post ID and last-modified timestamp. At the time of testing, the response contained 3,939 unpublished/non-public IDs across 27 content types, including press-release, mission, feature, page, people, event, and podcast.

I confirmed these IDs are genuinely non-public (not just already-live content) by checking them against the standard WordPress REST API and the public site: sampled IDs return 401 Unauthorized from /wp-json/wp/v2/posts/{id} (the object exists but access is forbidden) or 404 Not Found from the public site. I also found one ID from the leaked list that has since been published — it now 301-redirects to its live URL — which confirms the endpoint tracks NASA's real draft-to-publish pipeline rather than returning stale data.

I did not open, read, or harvest the contents of any individual draft. Per NASA's VDP rule to stop testing immediately upon encountering non-public/sensitive data, I halted after confirming the exposure was real.

Business Impact

This exposes NASA's internal editorial pipeline to anyone on the internet. Even without full body text, disclosing the existence, internal ID, content type, and last-edit timestamp of embargoed press releases and mission/feature announcements is sensitive — it signals that an announcement is in preparation and lets an attacker monitor edit activity or detect the moment an embargoed item goes live. It also hands out precise internal IDs for thousands of non-public objects, removing the guesswork for any future attempt to reach draft content through another endpoint that doesn't enforce authorization correctly.

Activity