Security

Pulling video off the web, safely: SSRF guards and a loopback-only server

A private app still has to touch the internet for one thing: importing a video you linked to. That single outbound path takes untrusted input — so it gets the most paranoid code in the whole product. Here's how it's locked down.

Most of MediaFind never speaks to a server — that's the private-by-default story. But “bring this YouTube clip into my library” obviously has to make a request, and that request is built from a URL a person typed. Untrusted input plus an outbound fetch is the classic setup for SSRF — so this path is treated as hostile by default.

The attack: a URL that points somewhere it shouldn't

SSRF is when an attacker gets your process to make a request they control the destination of. A download box that accepts any URL is a textbook target. The dangerous destinations aren't on the public web at all — they're inside your own machine and network:

And a naïve blocklist on the hostname doesn't help, because of DNS rebinding: a domain can look perfectly public and still resolve to 127.0.0.1. You can't judge a URL safe by its spelling — you have to judge it by the IP it actually connects to.

The guard: resolve-then-check up front, then re-check at connect time

So the check lives where it can't be fooled: by the resolved IP, not the spelling of the host. The first line of defense runs up front, at parse time — the moment a URL is accepted, its hostname is resolved to a real address and that address is validated. If it's loopback, link-local, or private, the URL is rejected before any fetch is even attempted. Then, because a hostname that resolved to a public IP at parse time could resolve to 127.0.0.1 a moment later (DNS rebinding, a TOCTOU race), the same check runs again when the socket is about to connect: the connection re-resolves the host, pins the validated IP, and refuses it before a single byte is sent if it's now internal. Parse-time validation is the wall; connect-time re-resolution is the second wall behind it that closes the rebinding gap.

Pasted URL untrusted Resolution guard resolve hostname → IP at parse + connect time Public IP → allow fetch proceeds over verified TLS Private / link-local → block 127.0.0.1 · 169.254.169.254 10.x · 192.168.x · 172.16/12
The decision is made on the resolved IP — the one thing DNS rebinding can't disguise — first up front at parse time, then re-checked at connect time. Public addresses pass; loopback, link-local, and private ranges are refused before any request goes out.

Two more details round out the fetch path:

Defense in depth, not a single wall: the guard is the primary control, but it's layered — validate the resolved IP up front at parse time, re-validate at connect time to defeat DNS rebinding, verify TLS hostnames, and keep the fetchers behind one shared chokepoint so there's no second, weaker door. Security bugs cluster at the seams between components; the design minimizes the number of seams.

The other front door: the local web UI

MediaFind's interface is a small local web app. That's a lovely way to build a Mac app — and also a thing you must not accidentally expose to the network. Two measures keep it private:

State-changing requests are also CSRF-protected, so a random web page you visit can't quietly POST commands to your local server in the background.

The hardening, in one table

SurfaceControlStops
Download URLResolved-IP guard (parse-time + connect-time)SSRF, DNS-rebinding to internal hosts
HTTPS fetchHostname-verified TLSMan-in-the-middle on the import path
Scrape fallbackSame guard as yt-dlpA weaker second code path
Local serverBinds to 127.0.0.1 onlyOther devices reaching your UI
State changesCSRF tokenCross-site command injection

The principle

Privacy and security are the same discipline seen from two sides. The privacy story is about the data that never leaves; the security story is about the one path that does reach out, and making sure it can only go where you intended. Untrusted input gets treated as hostile, the dangerous destinations are blocked at the layer that can't be spoofed, and the local UI stays strictly local. Paste a link with confidence — the paranoia is built in.

Import from the web, without inviting it in

The one outbound path is the most hardened code in the app. Everything else stays on your Mac.

Download for macOS