Skip to main content

Confirm

Are you sure?

Security

How URLpipe protects your keys and your data

The short, specific answers to the questions a security review asks — each one a description of what the code does.

By · Last updated: September 2026

TL;DR

API keys and organization tokens are stored only as SHA-256 digests and shown once. Webhooks can be signed with HMAC-SHA256. URLs that point at IP addresses, internal hosts or custom ports are refused, and a page that resolves to a private address is not loaded. Results are private to your organization and deleted after 30 days. Everything runs in the EU. Report issues to contact@urlpipe.dev.

Free plan, no credit card. 1,000 credits a month.

Credentials

API keys and tokens are stored hashed

A project's API key is stored the way a password is: a SHA-256 digest and the first few characters, never the key itself. It is shown once, when it is created. Keys start with up_key_, so a person, a log line or a secret scanner can recognise one.

Rotating a key opens a 24-hour window in which the old key still works, so you can deploy the new one without an outage. If you rotated because a key leaked, revoke the old one and the window closes at once.

The MCP server uses organization tokens, stored the same way — a SHA-256 digest, shown once. A token can be read-only (it can read results and usage but cannot fetch a page, which is every operation that spends credits), limited to one project, or given an expiry date.

  • Passwords are hashed with bcrypt; one-time sign-in codes are stored hashed too.
  • Every endpoint is rate limited per key — see rate limits.

Webhooks

Webhooks prove they came from us

Turn on signing for a project and every delivery carries X-URLpipe-Timestamp and X-URLpipe-Signature: v1=<hex> — an HMAC-SHA256, with the project's secret, of <timestamp>.<raw body>. The timestamp is inside the signed string, so a captured delivery can't be replayed with a fresh one; reject old timestamps and verify against the raw bytes.

Rotating the secret signs every delivery with both secrets for 24 hours, newest first, so your endpoint can switch over in any order. Revoking stops the old one immediately. Verification code for several languages is in the webhook docs.

Webhook destinations are held to the same address rules as the URLs we fetch (below), checked when you set them and again at delivery, so a webhook can't be pointed at an internal service.

SSRF

What we refuse to fetch

Every URL — one you ask us to analyse, a webhook destination, the robots.txt we read before a visit — passes the same check before anything is requested. A URL is accepted only when it is:

  • an http or https URL of at most 2,048 bytes, with no control characters;
  • addressed to a domain name — never an IP address in any notation a browser accepts (dotted, decimal, octal, hex, shortened or IPv6), never localhost, never a single-label name;
  • not under an internal suffix: .local, .localhost, .internal, .lan, .home or .arpa;
  • free of credentials — no user:pass@ before the host;
  • on the scheme's default port.

The questions are asked of the host as the browser will resolve it — after IDNA mapping, percent-decoding and dropping a trailing dot — not of the string as typed, so 127%2e0%2e0%2e1 and its cousins are refused like 127.0.0.1.

That check is DNS-free, so more run where they can't be fooled. On a page visit, a connection to an address in a private, loopback, link-local or other reserved range ends the visit — including one reached through a redirect or a DNS answer that points somewhere internal. And every machine that loads pages, the Lighthouse auditor included, is blocked from private networks by an egress policy at the network layer. A refused URL is a 422 that names the reason, and costs nothing.

Your data

Who can see a result, and for how long

Results are private to your organization. A stored result answers your organization's requests and nobody else's; another account asking for the same URL gets its own fetch. A result token only works with the key of the project that made the request.

Screenshot links are the one exception, by design. X-Result-Url is a signed link that needs no key, so you can put it in an <img> tag. Anyone holding that link can load that one image until the result expires.

Retention. Results — the Markdown, HTML, screenshots and extractions we produce — are deleted 30 days after they are generated. Your request history (the URL, options, timing and outcome of each request) stays in your dashboard until you delete the project or organization. Routine backups rotate out within 30 days.

Deletion. You can close your account from Account settings, and an admin can delete the whole organization — projects, API keys, request history and stored results — from Organization settings. Both take effect immediately and can't be undone.

Where. Fetching, rendering and storage happen in the European Union on every plan. The only step that can leave the EU is the language model behind /meta, /summarize and /keywords, and an organization can keep that in the EU too, at no charge — see data residency. We don't use the pages you fetch to train models.

Subprocessors

Who else touches your data

Pages are fetched and rendered on our own infrastructure; the URLs you submit are not passed to a third-party rendering service. The third parties below each receive only what their job needs — the same list as the privacy policy:

ProviderWhat for
Language-model providersPage content for /meta, /summarize and /keywords only, over TLS, to providers that neither log nor retain prompts nor train on them. EU-only when EU data residency is on.
StripePayments, invoices and VAT for paid plans. Card numbers never reach us.
SMTP2GOTransactional email.
Cloudflare TurnstileA bot check on the sign-up form.
Google and GitHubSign-in, only if you choose it.
Honeybadger and Scout APMError reports and performance monitoring, which can include the request that failed.
Hosting and storage providers in the EURun the application and store account and request data.

The site

Signing in and the dashboard

  • TLS everywhere.
  • Sign in with email and password, or with Google or GitHub.
  • Sign-up is behind a bot check, and a new account confirms its email address before its API key works.
  • The site sends a content security policy that allowlists what may load, and the public pages use cookie-free analytics; the dashboard and sign-in pages run none.

Disclosure

Reporting a vulnerability

Email contact@urlpipe.dev with what you found, how to reproduce it and what it lets someone do. It goes straight to the person who wrote the code, and you'll get a reply from a human.

Please test only against your own account and projects, don't read or change other customers' data, and don't run load tests against the API — the rate limits apply to research too. Give us a reasonable chance to fix an issue before you publish it.

FAQ

Frequently asked questions

Does URLpipe store my API key?
Only as a SHA-256 digest and a short prefix. The key itself is shown once, when it is created, and cannot be read back — rotate it if you lose it.
How do I know a webhook came from URLpipe?
Turn on signing for the project and verify X-URLpipe-Signature: an HMAC-SHA256 of the timestamp, a dot and the raw body, with your project's secret.
Can URLpipe be pointed at internal addresses?
No. IP addresses in any notation, localhost, internal suffixes, credentials and custom ports are refused before a request is made, and a visit that connects to a private address is ended.
How long are results kept?
30 days from when they were generated, then deleted. Request history stays until you delete the project or organization.
Is my data processed in the EU?
Fetching, rendering and storage are in the EU on every plan. The AI endpoints' model calls can be kept in the EU with one organization setting, free.

Turn any URL into clean data in minutes.

Free plan, no card. Confirm your email and your API key is live — you'll be making real requests in minutes.