Vulnerabilities
JSONP vs CORS for Public Browser APIs
July 17, 2024
JSONP vs CORS for public browser APIs is a legacy script tag versus Fetch CORS. JSONP wraps JSON in a caller-chosen function name so a <script src> can read another origin. That skips Access-Control-Allow-Origin entirely. Any page can load the URL. Cookies on a simple GET, secrets in the JSON, and a guessable callback name all become the other site's data. CORS lets you name origins, methods, and credentials on purpose. Wildcard plus cookies is still wrong — see credentials vs wildcard. RoastMyOpsec app mode sends a bounded untrusted Origin and reads ACAO. It does not execute JSONP callbacks, does not pad callback names, and does not steal sessions.
The practical difference
CORS is a browser-enforced read policy on XHR/fetch. JSONP is 'this URL is a JavaScript program.' Search engines and <script> tags do not honor ACAO. If the body is user data or an API key, JSONP is a publish.
A callback query parameter is the tell. So is application/javascript that starts with foo({"ok":true}). Content-Type JSON plus CORS is the replacement.
How to choose a replacement
Public, non-sensitive reads: CORS * or a static allowlist, no cookies. Logged-in browser clients: named origin, credentials only if you must, SameSite on the cookie. Server-to-server: no JSONP, no CORS — use keys on the server. Do not add JSONP 'for old IE.'
| Pattern | Origin control | Cookie risk | Takeaway |
|---|---|---|---|
| JSONP ?callback= | None (script tag) | Simple GETs may send cookies | Retire it |
| CORS named ACAO | Explicit origin | Only with credentials true | Default for SPAs |
| CORS * | Every origin may read | Illegal with credentials | Public non-secret only |
| Server proxy | Your origin only | Your session stays first-party | Best for secrets |
What the roast can prove
A roast can show ACAO reflecting an untrusted Origin. It will not fetch ?callback=test or treat JSONP as a scored path. Hunt callback parameters in your own API docs and gateway. Pair with public JavaScript keys if the JSONP URL embeds a publishable token.
Common mistakes
The first mistake is leaving JSONP 'just for the marketing widget' on the same host as the account API.
The second mistake is reflecting the callback name without an allowlist of function identifiers — still retire JSONP rather than 'hardening' it.
The third mistake is adding CORS * and JSONP together and calling the stack modern.
Free audit the URL you own
RoastMyOpsec is a defensive public-surface roast: headers, cookies, sensitive paths, and more — no exploit payloads. Start with the free audit, then open the vault if the blurred findings look expensive.
Free audit nowFAQ
- Is JSONP a vulnerability by itself?
- It is a missing origin policy. If the payload is public weather, the risk is low. If it is user or account data, treat it as an exposure.
- Can I lock JSONP to one site?
- Not reliably. Script tags are not CORS. Move to CORS or a first-party proxy.
- Does RoastMyOpsec detect JSONP?
- No. It does not execute callbacks. Check CORS headers and remove callback routes in your own review.
Sources
Related guides
Vulnerabilities
CORS Wildcard vs Allowlist for Public APIsVulnerabilities
crossdomain.xml vs CORS for Public Browser APIsVulnerabilities
Public JavaScript API Keys vs Server Secrets