Last month, security researchers found that JSONFormatter and CodeBeautify — two of the most popular online JSON tools — had been leaking saved data for years. Five years of JSONFormatter saves. One year of CodeBeautify. Over 80,000 files containing passwords, API keys, AWS credentials, Active Directory secrets. Governments, banks, telecoms, healthcare.
The "save" feature on these sites creates shareable URLs with predictable patterns. Attackers were actively scraping them. Researchers uploaded fake AWS keys and watched them get tested within 48 hours.
This isn't a bug. It's architecture. Bad architecture, but architecture.
The problem with "save and share"
When you paste JSON into an online formatter and hit save, that data has to go somewhere. Usually a database. Usually with a URL you can share.
That's convenient. It's also a liability.
https://jsonformatter.org/{id}
https://codebeautify.org/{formatter-type}/{id}
These URLs are guessable. Scrapable. And apparently, nobody was checking what people were pasting before storing it forever on a public endpoint. Oops.
Local-first as a security decision
I built fknjsn.com last year because I needed to compare JSON payloads side-by-side. API responses, config diffs, before/after debugging. The usual.
I made a deliberate choice: no backend. Everything lives in localStorage.
// that's it. that's the persistence layer.
localStorage.setItem('json-rows', JSON.stringify(state))
Your data never leaves your browser. There's no server to breach, no database to scrape, no shareable URLs to guess. When you close the tab, your JSON is still there. When you clear your browser data, it's gone. You control the lifecycle.
Revolutionary stuff. Also known as "not being stupid."
What you give up
No sharing. If you want to send JSON to a colleague, you copy-paste it like an animal. There's no "generate link" button.
For my use case, that's fine. I'm usually comparing things I don't want to share anyway — API responses with auth tokens, config files with secrets, debug output with customer data.
If you need collaboration, this isn't the tool. But if you're pasting sensitive data into a formatter, maybe ask yourself: do I actually need that link? Or do I just click buttons because they're there?
The localStorage tradeoff
localStorage isn't encrypted. Anyone with access to your machine can read it. That's a real consideration.
But compare the threat models:
Online formatter with save feature:
- Data stored on third-party server
- Predictable URLs enable scraping
- You trust their security practices (lol)
- Data persists indefinitely unless manually deleted
- Breach affects all users at once
localStorage:
- Data stored on your machine
- No network exposure
- You trust your own device security
- Data cleared with browser data
- Breach requires physical/remote access to your specific machine
For most developers pasting API responses, the second model is dramatically safer. Unless you're worried about your cat.
Implementation is trivial
The entire persistence layer is a debounced write on state change:
watch(rows, () => {
clearTimeout(saveTimeout)
saveTimeout = setTimeout(() => {
localStorage.setItem('json-rows', JSON.stringify({
rows: rows.value,
selectedRowId: selectedRowId.value
}))
}, 500)
}, { deep: true })
On load, read it back:
onMounted(() => {
const saved = localStorage.getItem('json-rows')
if (saved) {
const state = JSON.parse(saved)
rows.value = state.rows
selectedRowId.value = state.selectedRowId
}
})
No auth. No API. No database migrations. No GDPR compliance headaches because you're not collecting anything. Turns out the easiest way to secure user data is to not have it.
When to use what
Use an online formatter when:
- You're working with public, non-sensitive data
- You genuinely need to share a link
- You trust the service and have reviewed their data practices
Use a local-first tool when:
- You're handling API responses, configs, or debug output
- The data might contain secrets, tokens, or PII
- You don't need collaboration
- You'd rather not think about whether some random site is storing your pastes forever
Try it
fknjsn.com — paste JSON, compare side-by-side, filter/search within each block. Everything stays in your browser.
The whole thing is a single HTML file. View source if you want to verify there's no tracking, no analytics, no sneaky POST requests. There's nothing to sneak.
The name is pronounced exactly how you think it is.
Top comments (0)