NASA APIs Security Audit: 5 Findings, Including X-Powered-By: appdat
https://api.nasa.gov/planetary/apod?api_key=DEMO_KEYAbout This API
api.nasa.gov is the consolidated open-data API gateway for the U.S. National Aeronautics and Space Administration. It fronts a pool of independent NASA datasets — Astronomy Picture of the Day (APOD), Near Earth Object Web Service (NeoWs), Earth Polychromatic Imaging Camera (EPIC), the Earth Observatory Natural Event Tracker (EONET), Mars Rover Photos, NASA Image and Video Library, the Exoplanet Archive, TechPort, and several more — behind a single host with a single key-scheme. The data is, with very few exceptions, public-domain U.S. government work product. The reach is enormous: countless museum kiosks, classroom projects, mobile apps, browser extensions, and the canonical 'fetch the photo of the day' demo in essentially every introductory fetch() tutorial that wants something with a real authoritative source behind it.
The APOD endpoint specifically — /planetary/apod — has been NASA's public face on the web since June 1995. Each day a different image, photograph, or graphic of our universe is featured along with an explanation written by a professional astronomer. The HTTP API was added later as a way for downstream apps to pull the same content programmatically. APOD is the most-called endpoint on api.nasa.gov by a wide margin.
NASA's published auth model is unusual and worth describing precisely. There is no signup-required-to-read flow. Any caller can use the literal string DEMO_KEY as the api_key value and receive 200 responses, subject to a documented per-IP throttle (30 requests/hour, 50 requests/day on DEMO_KEY). Developers who register on api.nasa.gov receive a personal key with higher limits (1,000 requests/hour). The key is not a secret in the cryptographic sense — it identifies the caller for rate-limiting and analytics purposes, not for authorization. The data behind every endpoint is the same regardless of which key calls it.
This audit is the latest in middleBrick's public-API case-study series. We scanned https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY. Five findings came back. One — the X-Powered-By disclosure — is a small but interesting fingerprint that points at the gateway technology behind the whole service.
Threat Model
The threat model for api.nasa.gov is shaped by two facts that don't usually appear together: the data is fully public-domain (so confidentiality is not in the model), and the operator is a federal agency (so integrity, availability, and supply-chain trust are weighted heavily). An attacker has no path to private data through the API because there is no private data behind the API. The interesting attack surfaces are availability, integrity of the cached responses being served to downstream consumers, and the propagation patterns the API teaches.
Availability
NASA's documented rate-limit on DEMO_KEY (30/hour/IP) is enforced at the gateway. A distributed scraper that rotates source IPs can drive aggregate load against the backend regardless. The API gateway absorbs this far better than the upstream content services, but a sustained DDoS targeting APOD specifically would also affect the canonical apod.nasa.gov website that pulls from the same content. This isn't theoretical — DDoS against federal informational sites happens regularly enough that CISA tracks it.
Integrity of downstream consumers
Thousands of educational apps and museum kiosks render APOD content directly into their UI. If api.nasa.gov ever served attacker-controlled content (via a compromised origin, a poisoned cache, or a hijacked CDN edge), the blast radius would include children's classrooms and museum exhibits worldwide. This is exactly why federal informational APIs receive disproportionate attention from agency security teams: the consumers are sometimes literally school children. Mitigations live at the gateway layer (NASA's Apigee deployment, which the X-Powered-By header points at), the CDN, and the upstream origin.
Propagated patterns
Because api.nasa.gov is a tutorial favorite, the patterns it teaches matter. The two patterns most commonly inherited by tutorial students:
Wildcard CORS. Every response carries Access-Control-Allow-Origin: *. Correct for public-data-from-anywhere; wrong as a default to copy into an authenticated personal API.
API key in URL query string. The documented call pattern is ?api_key=YOUR_KEY. NASA's keys aren't sensitive, but the habit of putting credentials in the query string (where they appear in browser history, server access logs, and Referer headers) propagates into apps where the key is sensitive. The correct alternative is X-Api-Key as a request header — which api.nasa.gov also accepts but does not lead with in its documentation.
Methodology
middleBrick ran a black-box scan against https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY. The scan was read-only — no destructive HTTP methods, no probe payloads beyond the standard set. Twelve security checks executed across OWASP API Top 10 categories. Five returned findings; seven returned clean.
The five findings:
- CRITICAL: API accessible without authentication (CWE-306, structural for an open-data API)
- HIGH: CORS allows all origins (CWE-942, structural for an open-data API)
- LOW: Missing Cache-Control header (CWE-693, hygiene)
- LOW: No URL versioning detected (CWE-1059, hygiene)
- LOW: Technology exposed via
X-Powered-By: appdat(CWE-200, framework disclosure)
The seven clean negatives are worth noting because they are what kept the score at A: no IDOR signal (the APOD response identifies a date, not a numeric resource ID), no data-exposure pattern (the response body is a clean JSON object with title/explanation/url/media_type — no email, token, password, or PII shapes), no mass-assignment surface, no SSRF surface (the response embeds asset URLs but they are NASA-controlled), no unpaginated-collection finding (the canonical APOD response is a single object, not a list), no rate-limit-headers finding (NASA actually does emit X-RateLimit-Limit and X-RateLimit-Remaining, which the scanner correctly recognized), and no dangerous-method advertisement.
The CRITICAL and HIGH findings are correct readings of the protocol-level state and would be CRITICAL/HIGH on any commercial API. We deliberately do not silence severity by category, because the same scan output is meant to be readable on a federal open-data API and on a misconfigured private one. The contextual interpretation belongs to the analyst, not the scanner.
Results Overview
api.nasa.gov scored 90 out of 100 — an A grade. Five findings: one CRITICAL, one HIGH, zero MEDIUM, three LOW.
The CRITICAL is 'API accessible without authentication.' This is the single most-flagged finding in our entire public-API series and the most-misread by people unfamiliar with how public-data APIs operate. NASA's published model is that the api_key parameter is a rate-limiting and analytics identifier, not an authorization credential. DEMO_KEY is a documented constant that anyone can use. The data behind the API is public-domain U.S. government work product. There is no authorization decision to make — this is correct behavior for an open-data API, and the scanner's CRITICAL severity reflects the protocol-level state (no credential gating) rather than a contextual risk assessment.
The HIGH is the wildcard CORS finding — also structural for a public-data API meant to be embedded into educational apps from arbitrary origins.
The three LOWs are the substantive ones for the maintainer's queue:
- Missing Cache-Control header. APOD responses have a daily cadence — the same image is returned for every request on the same date — and serving them without explicit cache-control means downstream caches and browsers apply heuristic caching that can be wildly off the actual freshness contract.
- No URL versioning. The path is
/planetary/apod, not/v1/planetary/apod. NASA cannot meaningfully version-break this URL because every existing tutorial in the world hard-codes the unversioned path; documenting the implicit v1 contract is the lower-cost remediation. - X-Powered-By: appdat. Most interesting of the three.
appdatis the historical product name for what is now Google Apigee — specifically the on-premises Apigee Edge MicroGateway that NASA's developer portal documents using. The header is set by Apigee's default response policies and reveals the gateway technology fronting api.nasa.gov.
For comparison with prior case studies in this series:
- SWAPI: 4 findings (A, 91)
- NASA APIs (APOD): 5 findings (A, 90) ← here
- Rick and Morty: 9 findings (B, 78)
- FakeStoreAPI: 10 findings (C, 75)
- HTTPBin: 11 findings (B, 82)
- JSONPlaceholder: 11 findings (C, 73)
- PokéAPI: 12 findings (B, 76)
- Random User: 12 findings (B, 79)
- DummyJSON: 13 findings (B, 75)
- ReqRes: 17 findings (C, 73)
NASA's APOD is one of the cleanest scans in the pool, just below SWAPI by a single point. That isn't an accident — federal public-data APIs go through agency security review, FISMA controls, and (for any API hosted on a FedRAMP-accredited platform) continuous monitoring requirements that no commercial mock has any reason to apply.
Detailed Findings
API accessible without authentication
The endpoint returned 200 without any authentication credentials.
Implement authentication (API key, OAuth 2.0, or JWT) for all API endpoints.
CORS allows all origins (wildcard *)
Access-Control-Allow-Origin is set to *, allowing any website to make requests.
Restrict CORS to specific trusted origins. Avoid wildcard in production.
Missing security headers (1/4)
Missing: Cache-Control — sensitive response caching.
Add the following headers to all API responses: cache-control.
No API versioning detected
The API URL doesn't include a version prefix (e.g., /v1/) and no version header is present.
Implement API versioning via URL path (/v1/), header (API-Version), or query parameter.
Technology exposed via X-Powered-By: appdat
The X-Powered-By header reveals framework details.
Remove the X-Powered-By header in production.
Attacker Perspective
An attacker has effectively no productive work to do against api.nasa.gov in the conventional 'access something private' sense. The data is public, the keys are documented, the rate limits are published. The interesting reconnaissance value is in what the API quietly reveals about its own infrastructure.
The X-Powered-By: appdat fingerprint
The appdat string is not a household name. It is the legacy product identifier for Apigee Edge MicroGateway. Apigee was acquired by Google in 2016 and the product line has been rebranded multiple times — Apigee Edge, then Apigee X under Google Cloud — but the on-premises and hybrid components retained the appdat banner string in default response policies for a long time. NASA's developer portal documentation and FedRAMP package describe the agency's API gateway as Apigee, hosted on a FedRAMP Moderate-authorized platform, which matches the fingerprint exactly.
For an attacker, this is incremental information. The presence of Apigee in front of an API tells you that there is a gateway with its own attack surface (custom policies, JavaScript callouts, KVM stores), that the upstream services are not directly exposed, and that authentication-and-rate-limit logic is centralized at the gateway rather than in the upstream services. None of that is exploitable on its own — Apigee is a mature, audited platform with a serious security pedigree — but it does shape how a determined attacker would approach reconnaissance against any other api.nasa.gov endpoint. They would look for inconsistencies between gateway-level and origin-level behavior, header-injection paths, and policy-bypass tricks specific to Apigee deployments.
The DEMO_KEY rate-limit boundary
The published 30-requests/hour DEMO_KEY ceiling is enforced per source IP. A scraper that rotates source IPs (commercial residential proxy networks make this trivial) can move past the documented limit by orders of magnitude. The interesting question is not whether this is technically possible — it obviously is — but whether anyone has cause to. The data is free, the personal-key tier is also free, and there is no gating that a higher request volume would unlock. The most plausible misuse is a denial-of-service against the upstream content service via aggregate scraper load on a popular endpoint, which is mitigated at the gateway, the CDN, and the origin.
What's notable in its absence
The scan's clean negatives matter for an attacker triaging which federal API to spend time on. No SSRF surface, no IDOR signal, no data-exposure pattern, no mass-assignment field shapes. The APOD endpoint returns exactly the shape it documents: {date, explanation, hdurl, media_type, service_version, title, url}. There is nothing to mass-assign, no nested object with sensitive shapes, no internal_id field accidentally serialized into the response. The attack surface is small and the fingerprinting is clean. For someone hunting for federal-API mistakes, APOD is a poor target — the agency obviously runs a tight enough gateway operation that the easy mistakes have been weeded out.
Analysis
The most interesting finding is the X-Powered-By disclosure. Let's walk through it.
$ curl -I 'https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY'
HTTP/2 200
x-ratelimit-limit: 40
x-ratelimit-remaining: 39
access-control-allow-origin: *
x-powered-by: appdat
...
The x-powered-by: appdat header is set by Apigee Edge's default response template. appdat is the legacy banner string from before the Apigee/Google Cloud rebranding. Today's Apigee X has different defaults, but on-premises and hybrid Apigee deployments — the kind a federal agency operating under FedRAMP would be most likely to run — still emit the historical banner unless explicitly suppressed. The fix is a one-line response policy at the gateway:
<AssignMessage name="strip-poweredby">
<Remove>
<Headers>
<Header name="X-Powered-By"/>
</Headers>
</Remove>
<AssignTo type="response"/>
</AssignMessage>For NASA the disclosure is informational rather than enabling — Apigee is a hardened, frequently-audited gateway, and an attacker who learns 'this is fronted by Apigee' has not learned a vulnerability. The reason the finding still matters is institutional: federal agency security guidance (NIST SP 800-53 SI-11, Information Output Filtering) explicitly calls out unnecessary product-disclosure headers as a finding worth closing. An agency security review would flag this exactly the way our scanner does.
The Cache-Control finding. APOD has a clear daily cadence. The same image is returned to every caller on the same date. Yet the response carries no Cache-Control, no ETag, no Last-Modified. Downstream caches apply heuristic freshness based on response age, which is approximately never what the agency wants on content with a known refresh time. The remediation is a one-line policy at the gateway:
Cache-Control: public, max-age=3600, s-maxage=21600Plus an ETag derived from the date+image hash. This would also reduce origin load proportionally to the cache hit rate.
The CORS wildcard. Correct for an open-data API meant to be called from arbitrary educational apps. The conventional alternative — an explicit origin allowlist — is impractical here because the legitimate consumers are 'every webpage in the world that wants to render APOD.' Wildcard CORS on a no-credentials, no-cookies, public-data endpoint is the right configuration. The finding is fired by the scanner heuristic, which can't know that.
The 'no authentication' CRITICAL. NASA's auth model is rate-limit-and-attribution, not authorization. DEMO_KEY is a published constant. The data behind every endpoint is public-domain. The CRITICAL severity is correct as a protocol-level reading — no credential validation occurs — and is the right finding to keep visible, because the same scanner runs against private APIs where 'no auth required' would be a real exposure.
No URL versioning. The unversioned /planetary/apod path is decades old and embedded in tens of thousands of consumers. Any breaking versioning change would orphan museum kiosks running unmaintained code. NASA's lower-cost remediation is documenting the implicit v1 contract in the developer portal and reserving /v1/planetary/apod as an alias if a v2 ever lands.
Industry Context
api.nasa.gov sits in the public-data federal-API niche alongside data.gov, weather.gov (NWS API), the Federal Reserve's FRED API, USAJobs.gov's API, and the U.S. Census Bureau's APIs. Among that peer group, NASA's API is one of the most-consumed by independent developers — APOD alone serves an enormous tail of small applications and educational projects.
Federal compliance posture
Public-facing federal APIs operate under a different regulatory frame than commercial APIs. The relevant frameworks:
FISMA (Federal Information Security Modernization Act). Federal agencies must categorize information systems (Low/Moderate/High impact under FIPS 199) and apply the corresponding NIST SP 800-53 control baselines. A public-data API like api.nasa.gov is typically categorized Moderate due to integrity-of-public-information concerns, even though confidentiality is Low. Continuous monitoring is required.
FedRAMP. If the API is hosted on a third-party cloud platform — and api.nasa.gov is — the platform itself must hold a FedRAMP authorization. NASA's developer portal documentation describes the platform as FedRAMP Moderate-authorized. Apigee X has FedRAMP Moderate ATO, which matches.
21st Century IDEA Act and OMB Memo M-19-23. Federal websites and digital services have explicit requirements for accessibility, mobile-friendliness, search-engine indexing, and (relevant here) machine-readable data formats. APOD's JSON API exists in part to satisfy this requirement.
Agency-specific. NASA Procedural Requirements 2810.1 ('Security of Information and Information Systems') is the agency-internal companion to NIST SP 800-53. It applies to api.nasa.gov.
What this changes for the findings
The X-Powered-By disclosure is the finding most affected by the federal context. On a commercial mock API, X-Powered-By disclosure is a low-priority hygiene fix. On a federal API, NIST SP 800-53 SI-11 ('Information Output Filtering') is an explicit control and product-banner headers are routinely flagged in agency assessments. Closing this finding is not just hygiene; it's an audit-friendly action that reduces the agency's findings-list at the next FISMA assessment cycle.
The 'no authentication' CRITICAL is where the federal context most clearly diverges from a commercial reading. NASA's model is correct and well-documented; the finding is structural rather than actionable.
OWASP API Top 10 mapping
API1 (broken authentication, by structural design — public-data API). API3 not present (no IDOR signal). API8 (security misconfiguration) covers Cache-Control, X-Powered-By, and CORS-on-an-open-API. API9 (improper inventory management) covers the no-versioning finding. The remaining six categories are not represented because the surface is too disciplined to produce them.
Remediation Guide
X-Powered-By: appdat disclosure
Add an Apigee response-policy that strips the X-Powered-By header. One-line policy attached to the relevant API proxy.
<!-- Apigee AssignMessage policy: strip-poweredby.xml -->
<AssignMessage name="strip-poweredby">
<DisplayName>Strip X-Powered-By</DisplayName>
<Remove>
<Headers>
<Header name="X-Powered-By"/>
</Headers>
</Remove>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" type="response"/>
</AssignMessage>
<!-- Attach to ProxyEndpoint response flow:
<PreFlow><Response><Step><Name>strip-poweredby</Name></Step></Response></PreFlow>
--> Missing Cache-Control on daily-cadence resource
Add Cache-Control + ETag at the Apigee gateway. APOD updates once per UTC day, so a 1-hour browser TTL and 6-hour shared-cache TTL are conservative.
<!-- Apigee AssignMessage policy: apod-cache-headers.xml -->
<AssignMessage name="apod-cache-headers">
<Add>
<Headers>
<Header name="Cache-Control">public, max-age=3600, s-maxage=21600</Header>
</Headers>
</Add>
<AssignTo createNew="false" type="response"/>
</AssignMessage>
<!-- Pair with an ETag policy that hashes date+url:
etag = sha256(response.body.date + response.body.url)
--> URL versioning (lower-cost workaround)
Document /planetary/apod as the implicit v1 in the developer portal. If a future v2 is needed, add /v1/planetary/apod as an alias before introducing /v2/. Don't break the unversioned path — it's embedded in consumers that will never be updated.
# Apigee BasePath alias
# proxy.xml — add /v1 as an alternate basepath
<HTTPProxyConnection>
<BasePath>/planetary/apod</BasePath>
<VirtualHost>secure</VirtualHost>
</HTTPProxyConnection>
# plus a parallel proxy with BasePath /v1/planetary/apod that routes to the same TargetEndpoint Consumer pattern: API key in query string
When you eventually move from DEMO_KEY to a personal key, send it in the X-Api-Key header rather than the api_key query parameter. api.nasa.gov accepts both. The header form keeps the key out of browser history, server access logs, and Referer headers.
// Don't:
fetch('https://api.nasa.gov/planetary/apod?api_key=' + MY_KEY);
// Do:
fetch('https://api.nasa.gov/planetary/apod', {
headers: { 'X-Api-Key': MY_KEY }
}); Consumer pattern: respect daily cadence
APOD content updates once per UTC day. If your app is calling APOD more than once per day, you're wasting your rate-limit budget and contributing to NASA's gateway load. Cache the response keyed by date.
// Cache APOD by date for 24h
const todayUTC = new Date().toISOString().slice(0, 10);
const cacheKey = `apod:${todayUTC}`;
let apod = await cache.get(cacheKey);
if (!apod) {
const res = await fetch('https://api.nasa.gov/planetary/apod', {
headers: { 'X-Api-Key': MY_KEY }
});
apod = await res.json();
await cache.set(cacheKey, apod, { ttl: 86400 });
} Defense in Depth
For NASA's API gateway team, the action items are short and almost entirely at the Apigee layer.
1. Suppress X-Powered-By. A one-line response-policy fix at Apigee. Closes the framework-disclosure LOW and removes a NIST SI-11 control finding from the next FISMA assessment.
2. Add Cache-Control to APOD responses. APOD has a daily cadence and a CDN in front of the gateway. Cache-Control: public, max-age=3600, s-maxage=21600 aligns the cache contract with the actual freshness model. Pair with an ETag for conditional-GET support. Reduces origin load proportionally and closes the LOW finding.
3. Document the implicit v1. Adding /v1/planetary/apod as an alias for the existing path costs nothing and gives NASA a versioning escape hatch. Alternatively, the developer portal could explicitly declare the unversioned URL as 'v1, no future versions planned' to close the spirit of the finding.
4. (Optional) Lead with X-Api-Key in documentation. The API already accepts X-Api-Key: YOUR_KEY as an alternative to the query-string parameter. Documenting it as the primary call pattern, with the query-string form as a secondary, would discourage tutorial students from inheriting the credential-in-query-string habit when they later build their own APIs with sensitive keys.
5. Don't change the auth model. The DEMO_KEY public-rate-limited model is appropriate for an open-data API. Adding 'real' authentication would break every existing consumer for no security benefit.
For consumers — the apps and tutorials that use api.nasa.gov — the defenses are: cache responses (the data is daily-cadence; you should not be calling APOD more than once per day), respect the documented rate limit and request a personal key if you need more, and use the X-Api-Key header rather than the query-string parameter when you eventually move from DEMO_KEY to a personal key. Don't log the URL with the key in it. When you build your own APIs, don't inherit the wildcard CORS or credential-in-query-string patterns into anything that handles authenticated user data.
Conclusion
api.nasa.gov's APOD endpoint scored 90/100 with five findings — the second-cleanest result in our public-API case study series, just behind SWAPI. The two highest-severity findings (no-auth CRITICAL, wildcard-CORS HIGH) are structural to a federal open-data API and reflect the architecture working as designed. The three LOWs are the actionable queue: a missing Cache-Control header on a daily-cadence resource, an unversioned URL path, and the X-Powered-By: appdat banner that fingerprints the underlying Apigee gateway.
For maintainers building public-data APIs at any scale, NASA's APOD is a worked example of what disciplined response-shape design looks like in a federal context: rate-limit-headers emitted, response shape clean, no SSRF or IDOR or data-exposure surface, no internal metadata leaking. The agency cannot fix the structural findings (no-auth, wildcard CORS) without breaking the model that makes the API useful, but the three hygiene fixes are all one-line policy changes at the Apigee gateway.
For consumers — students, museum operators, app developers — the API is exactly what NASA describes: a public-domain, rate-limited, no-real-secret-required interface to canonical NASA datasets. Use it. Cache the responses. Move from DEMO_KEY to a personal key as soon as your usage exceeds 30 requests per hour. And when you build your own APIs later, don't carry NASA's open-data patterns into systems where the data isn't actually open.
Scope reminder: api.nasa.gov is a multi-endpoint surface (APOD, NeoWs, EPIC, EONET, Mars Rover Photos, and others). This audit covered the APOD endpoint only. Other endpoints with different response shapes — Mars Rover Photos returns paginated arrays, NeoWs returns deeply nested objects — would likely produce a different finding profile under the same scan.