Sanitize a curl command before you share it

Runs locally in your browser. Your file never leaves your device.

By processing a file or pasted text here, you agree to the Terms.

Pasting sanitizes automatically; the button re-runs after edits. Up to 2 MB.
…or sanitize a file instead

Pick a plain-text file (or drop one onto the box above). For whole terminal logs, the log file redactor handles up to 20 MB.

What gets sanitized

“Passwords & secrets in key=value” also governs the name-based masks this page adds on top: sensitive header names (authorization, x-api-key, …), credential-named query and form parameters, and JSON body keys. Cookie values, -u passwords, URL userinfo passwords, and --oauth2-bearer are masked by grammar position and stay on regardless of toggles.

A copied curl command is your logged-in session, serialized

“Copy as cURL” exists to make requests reproducible, and it is very good at that — too good to paste anywhere public. The command DevTools puts on your clipboard carries every cookie your browser held for that site (the session cookie that is your login, the CSRF token, the analytics IDs), the Authorization header if the app sends one, any API keys riding in custom headers, and the entire request body with whatever the form or API call contained. Anyone who runs it is you, until the tokens expire or get revoked. Pasting one into a GitHub issue, a support ticket, a team chat, or an AI assistant hands your ambient identity to everyone who can read it — and manual redaction reliably misses the third cookie in a fat cookie: header.

What gets masked — and what the output looks like

Headers with credential-shaped names (authorization, proxy-authorization, x-api-key, x-auth-token and relatives) keep the name and the scheme word but lose the credential: authorization: Bearer [SECRET-1] still tells the reader what kind of auth the request used. Cookie headers and -b strings are masked per cookie, by position — every value, names kept — because the format itself says what they are. -u user:password keeps the username and masks only the password (same rule as URL user:pass@host userinfo): the username is often the reviewable, repro-relevant half, and an email-shaped one is still caught by the email pattern. Credential-named query parameters (token=, api_key=, sig= …) are masked in URLs and --referer values. Form bodies get the same key=value credential detection as every tool on this site; strict-JSON bodies are walked key-by-key, so "access_token" three levels deep is masked and re-serialized minified. And one value seen in several places — header, cookie, body — becomes the same placeholder, so the sanitized command still shows one credential doing all three jobs.

Everything is spliced into your original text: quoting style, argument order, backslash or caret line continuations, even the $ prompt in pasted scrollback stay byte-for-byte intact outside the masked spans. Both flavors DevTools emits are understood — bash/POSIX (single quotes, $'…', backslash continuations) and Windows cmd ("" escapes, caret continuations) — and prose around the commands is scanned with the ordinary pattern engine, because real pastes are terminal scrollback, not clean one-liners.

The URL host stays readable — on purpose

Masking api.example.com would gut the repro; the endpoint is usually why the command is being shared at all. So public-looking hosts stay. The flip side: hosts that look like private infrastructure — single-label machine names like buildcache:9945, intranet suffixes like registry.corp — are flagged in the review panel, unchanged, for your call; and host:port shapes with strong enough evidence are masked by the shared detection engine, the same conservative hostname handling as the stack trace cleaner. A private host with a public-looking name will sail through — read the preview.

What it can miss — read this before you share

Detection is pattern-based and best-effort — expand for what can slip through.

Detection is pattern-based and incomplete by construction, and this page is deliberately not a shell parser — it does quote-aware tokenization, nothing more. Command substitutions ($(…), backticks) and variable references stay literal text; a command with an unterminated quote falls back to plain pattern scanning and says so; PowerShell quoting is not understood at all (DevTools’ “Copy as PowerShell” emits a different command entirely). A secret in a custom header with a bland name is only caught if its value matches a known pattern or is long and random enough for the suspicious-string flagger — random tokens under about 20 characters stay below its statistical floor, and prose-shaped secrets are invisible to it. Inline bodies that are not text are left byte-identical and flagged, and @file bodies reference contents this page never sees. The side-by-side preview exists so the final human pass takes seconds — do it.

Sharing a whole capture instead of one request? A HAR file is the many-request version of this problem — the HAR file sanitizer applies the same header, cookie, and body treatment across every entry.

Frequently asked questions

Does this page send my curl command anywhere?

No. This is a static page with no server behind it, and its Content-Security-Policy is set to connect-src ‘none’ — the browser itself refuses to let this page make any network request, to us or to anyone. You can verify that: open DevTools, watch the Network tab, and paste a command — no request carries your text. Sanitizing runs in this tab’s memory and nothing persists after you close it.

What does “Copy as cURL” actually capture?

The whole ambient identity of your browser session at that moment: every cookie your browser had for that site (session, CSRF, analytics, all of them), the Authorization header if the app uses one, API keys in custom headers, and the full request body. Pasting one into a ticket, a chat, or an AI assistant is functionally the same as handing over your logged-in session — anyone who replays it is you until the tokens expire.

Will the sanitized command still run?

It still parses and executes — quoting style, argument order, and line continuations are preserved byte-for-byte outside the masked spans, and the replacement placeholders are plain bracketed tokens that are safe in every quoting context this page handles. Our test suite re-parses every sanitized command and additionally checks bash syntax on real output. The server will of course reject the placeholder credentials — that is the point; whoever needs a working repro substitutes their own.

Why is the URL host still visible?

Because the endpoint is usually the reason you are sharing the command at all — masking api.example.com would gut the repro. The trade-off is deliberate and it cuts the other way for private infrastructure: hosts that look internal (single-label machine names, or suffixes like .corp and .internal) are flagged in the review panel for your call, and host:port shapes with strong enough evidence are masked by the shared detection engine. A public-looking hostname that is actually private will stay visible — check the review panel and the preview.

What about PowerShell?

DevTools’ “Copy as PowerShell” does not emit curl at all — it emits Invoke-WebRequest, which is a different command this page does not parse. And a curl command written with PowerShell’s own quoting (backtick escapes and continuations) is not understood either. Paste the bash flavor (Linux, macOS, WSL) or the Windows cmd flavor — the two things DevTools actually produces under “Copy as cURL”.

Why do repeated values get the same placeholder?

Each distinct value maps to a stable token like [SECRET-1], assigned in first-seen order — including across positions, so a session token that appears in the Authorization header, again in a cookie, and again in the JSON body becomes the same [SECRET-1] in all three places. Whoever reads the sanitized command can still see it is one credential doing all three jobs; the value itself is gone.