How your CVs stay private — Shortlane

shortlane.myclienta.com · last verified 24 October 2026 · Dansk
Your CV and the job text never leave your browser. The licence check is not sent CV text, a hash of a CV, a score, or a file name.

Checked against this code on 24 October 2026. The production network capture is from 22 July 2026, before the licence service existed.

What the automated test checks

A Playwright test in this repository runs two flows with the sample file cv-strong-mette-hansen.pdf and the finance-assistant job ad. The job-seeker flow attaches that PDF, pastes the job ad, and runs the check. The recruiter flow loads the built-in sample CVs and ranks them, and also attaches the same PDF. The test records every network request during those runs.

It fails if any request URL or body contains text from that CV or from the job ad, or bytes from the PDF. The only hosts it allows are this site, the licence Worker at https://cvmatch-licence.crcaway.workers.dev, Stripe (checkout.stripe.com, js.stripe.com, m.stripe.com, q.stripe.com), the public model and OCR file hosts (huggingface.co, hf.co, cdn.jsdelivr.net), and Cloudflare Web Analytics (cloudflareinsights.com). Requests to the licence Worker are checked the same way.

That is one run of those two flows. The test does not watch later visits, and it does not by itself stop a future change from adding a host.

1. Architecture

2. The browser blocks connections outside a short allow-list (CSP)

Every response carries a Content-Security-Policy. The browser blocks connections to any host outside this allow-list:

default-src 'self';
script-src 'self' 'wasm-unsafe-eval' https://cdn.jsdelivr.net
           https://static.cloudflareinsights.com;
worker-src 'self' blob:;
connect-src 'self' https://huggingface.co https://*.huggingface.co https://*.hf.co
            https://cdn.jsdelivr.net
            https://cvmatch-licence.crcaway.workers.dev https://checkout.stripe.com
            https://cloudflareinsights.com;
img-src 'self' data: blob:; style-src 'self' 'unsafe-inline'; font-src 'self';
object-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'none'

The browser refuses a connection to any other host before the request leaves the machine. Hugging Face and jsDelivr are there for the public model and OCR files. The licence server and Stripe Checkout are the other connections. The two cloudflareinsights.com hosts are Cloudflare Web Analytics: a cookieless page-view counter that never sees document content. form-action 'none' means no form can submit anywhere; frame-ancestors 'none' prevents clickjacking. An outbound POST to a host outside the list is blocked, and the browser logs a CSP violation.

3. Hardening headers

X-Frame-Options: DENY · X-Content-Type-Options: nosniff · Referrer-Policy: no-referrer · Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=() · Cross-Origin-Opener-Policy: same-origin · HTTPS enforced at the edge.

Cross-Origin-Embedder-Policy is not set. It would make ONNX Runtime load a threaded wasm file from a blob: URL, and script-src blocks that, so the embedding model would not load. The model runs in one thread.

4. Verify it yourself

5. GDPR position

Candidate CVs are processed on the recruiter's own device. The operator does not receive those CVs. Ranking is a guide for a person to review. No candidate is labeled rejected.

A buyer's browser does call the licence service. That service stores the licence record in section 1. Stripe keeps its own payment records under its own retention. Cloudflare hosts the site and the Worker.

6. Honest notes

← Back to the app