DEV Community

Shuttlewright
Shuttlewright

Posted on

Stop pasting client data into AI chats: a redaction step that runs entirely in your browser

Every day, developers and consultants paste real client data into AI chatbots. Names, emails, phone numbers, card numbers, amounts. The model gets a copy. So do its logs.

We built Shuttlewright Mask to break that habit without breaking the workflow. It runs entirely in your browser tab: paste text in, sensitive values become tokens, send the masked text to any AI, paste the answer back, and the real values are restored.

What it does

Paste a message like:

Hi, my name is Kwame Mensah. Please remind our client Abena Osei (abena.osei@example.com, 024 555 0134) that her invoice of GHS 4,250 is due Friday. Card on file: 4242 4242 4242 4242.

Mask returns:

Masked: Hi, my name is [PERSON_1]. Please remind our client [PERSON_2] PERSON_3 that her invoice of [AMOUNT_1] is due Friday. Card on file: [CARD_1]. 7 sensitive values replaced.

The token map - which token means which real value - never leaves your browser tab. Only the masked text goes to the AI. Paste the reply back and Mask restores the real values, so your client-facing text reads normally.

What it detects

Names, email addresses, phone numbers, card numbers, account numbers, postal addresses, and currency amounts.

The honest part

Our engine caught 26 of 26 seeded values (100%) across 12 synthetic business texts - on our own published test set. Your text is not our test set. No detector catches everything, and masked text can still carry identifying meaning (a rare job title plus a city can identify a person). That is why Mask shows you the masked version before anything is sent: you are the last check.

Privacy tooling that oversells is just marketing. The self-test runs on the site, unedited, so you can check it yourself.

Free and Pro

Free: the full mask-ask-restore loop in your browser, no account.
Pro ($9/month): removes the length limit and adds a relay that double-checks for leaks before anything is sent.

Try it: https://shuttlewright-mask.pillar-3a8.workers.dev/

Feedback welcome in the comments, especially texts where it misses something. That is how the detector gets better.

Top comments (22)

Collapse
 
omyvnss profile image
Om Yaduvanshi •

the restore step is the one i keep thinking about. masking is easy, but keeping the token map in the tab while the answer comes back from the model is where most of these tools quietly give up. and publishing the self-test unedited is the right move: 26/26 on seeded text says exactly what it says and nothing more.

Collapse
 
shuttlewright profile image
Shuttlewright •

You called it - the restore step just got the upgrade. Shipped today: Mask now highlights invented tokens and tokens the model altered (case/spacing/bracket changes) in the restored text, and never guesses. Altered tokens are left unrestored and marked instead of being silently fixed. Live on the app now: shuttlewright-mask.pillar-3a8.work...

Collapse
 
omyvnss profile image
Om Yaduvanshi • • Edited

same-day turnaround on this is impressive. never guessing is the whole point: a silently 'fixed' token that turns out wrong is worse than an unrestored one marked for review. marked beats confident-and-wrong every time.

Thread Thread
 
shuttlewright profile image
Shuttlewright •

Agreed on both halves. Marked beats confident-and-wrong every time - a wrong "fix" is the failure mode that looks like success.

And yes: the seeded set only proves the cases someone thought to seed. The per-input coverage is the human read of the masked preview before anything leaves - ten seconds of eyes on the exact text, not on a sample. That step is doing the real work; the test set is just regression insurance.

Thread Thread
 
omyvnss profile image
Om Yaduvanshi •

regression insurance is the right name for it. the test set is the policy, but the ten-second human read is what actually keeps you covered.

Thread Thread
 
shuttlewright profile image
Shuttlewright •

Exactly - and the read stays cheap because the tool already narrowed where to look. You skim the highlights instead of re-reading the whole document. That's what makes the habit survivable past the first week: ten seconds of attention aimed at the two or three places that could actually be wrong.

Thread Thread
 
omyvnss profile image
Om Yaduvanshi •

fair point, the narrowed view is what makes the habit cheap. do you track how often the highlighted tokens turn out to be real leaks? one week of false alarms and people start skimming past the real ones too.

Thread Thread
 
shuttlewright profile image
Shuttlewright •

Honest answer: no, and by design we can't. Nothing about your text or the highlights leaves the tab - no analytics, no counters, nothing to phone home with. The property that makes it safe to paste client data into is the same one that leaves us blind to how often the highlight is right.

Your fatigue point is the real failure mode of any alarm system, and the mitigation so far is scope rather than data: the highlight only fires on tokens that are unknown or altered against the map in your tab, not on every token, so the review stays at two or three spots instead of fifty. But you're right that "narrow" is a claim, not a measurement. A local-only way to mark a highlight as real or fine, kept in the tab and never uploaded, would be the honest version of tracking it. Taking that one back to the workshop.

Thread Thread
 
shuttlewright profile image
Shuttlewright •

Quick follow-up: your false-alarm point went straight into the workshop and shipped today. Mask now has a local-only Real / False alarm marker on each highlight. It shows you your own false-alarm rate over time and stores only counts by type in your browser - nothing is uploaded, so the no-tracking guarantee stays intact. shuttlewright-mask.pillar-3a8.work...

Thanks for the push. This was the right way to close the gap.

Thread Thread
 
omyvnss profile image
Om Yaduvanshi •

same-day shipping on a feature request is a good look. local-only counts is the right split: the alarm stats exist and nobody's text does. the real test is whether anyone keeps marking in week three.

Thread Thread
 
shuttlewright profile image
Shuttlewright •

That's the honest unknown, and it's ours too. With zero analytics, week-three marking rates are invisible to us by design - we can't measure the habit without breaking the promise, so we'll only ever know when people tell us.

Genuine question, since you're the one using it: what would make marking stick - one keystroke per highlight instead of a click, a once-a-week in-tab digest that lets you mark in bulk, or is marking at highlight time already the right moment? Whatever the answer is decides what gets built next.

Thread Thread
 
omyvnss profile image
Om Yaduvanshi •

keystroke for me. marking is a mid-thought action, and anything that pulls you out of the page to find a button kills it. bulk review later sounds efficient but it means re-reading everything twice. the cheapest test is ship the keystroke and see if the marking rate moves, that's a week of work against a question you're guessing at now.

Thread Thread
 
shuttlewright profile image
Shuttlewright •

Shipped already. Hover any highlight and press R for Real or F for False alarm - no button hunt, marking stays mid-thought exactly like you framed it. Counts by type, still stored only in your browser, and the shortcut ignores keystrokes while you're typing in a field. Just ran it end to end: masked a text, hovered a token, R and F moved the counters.

shuttlewright-mask.pillar-3a8.work...

Week three will tell us both whether the marking rate moves.

Thread Thread
 
omyvnss profile image
Om Yaduvanshi •

shipped in hours, as usual. for week three i'd watch the false-alarm rate more than the marking rate. a marker that cries wolf stops being mid-thought and turns into another thing to ignore.

Collapse
 
shuttlewright profile image
Shuttlewright •

Exactly right on both counts. The map never leaves the tab - restore is a local replace against it, so the wire only ever sees placeholders. And the self-test means what it says: 26/26 on our own seeded set, nothing more. Your own text is the real test, which is why the masked version stays on screen for a human check before anything is sent.

Collapse
 
omyvnss profile image
Om Yaduvanshi •

the 'nothing more' is the line that makes the 26/26 mean something. self-test proves the machinery works, the masked preview on screen is what proves it works on the input that actually matters. most tools would have shipped the first claim and buried the second.

Thread Thread
 
shuttlewright profile image
Shuttlewright •

That is the distinction we were trying to protect. A seeded test can only prove the cases someone thought to seed. Your own text always contains the case nobody thought of: a name format the seed set missed, a mixed-language line, a value that happens to look like a token. The preview is the catch for that - ten seconds of human eyes on the exact text about to leave, not on a sample. And it cuts the other way too: if the preview ever shows something masked wrong or missed entirely, that screenshot is the most useful bug report we could get.

Thread Thread
 
omyvnss profile image
Om Yaduvanshi •

right, the seeded set proves the detector works, but only eyes on the real text prove it works on your text. making the preview do the real coverage is the honest bit.

Collapse
 
officialmailkr profile image
오피셜메일 •

마스킹 결과를 전송 전에 사람이 확인하게 하고, 희귀한 직함과 도시 같은 문맥만으로도 식별될 수 있다고 밝힌 점이 좋습니다. 복원 단계에서는 모델이 토큰을 빠뜨리거나 새 토큰을 만들어 낸 경우도 별도로 표시되나요? 원문에 없던 값을 추측해 채우지 않고 미복원 항목을 검토 대상으로 남기는 테스트가 있으면 업무 메일 초안에 쓰기 더 안전하겠습니다.

Collapse
 
shuttlewright profile image
Shuttlewright •

좋은 질문 감사합니다. 복원 단계가 실무에서 쓸 수 있는지를 가르는 지점이 맞습니다.

현재 동작: 복원은 탭 안에만 남아 있는 토큰 맵을 기준으로 합니다. 모델이 토큰을 빠뜨린 경우 그 자리는 실제 값으로 채워지지 않고 토큰 그대로 남기 때문에 전송 전 검토 단계에서 바로 눈에 띕니다. 맵에 없는 값을 추측해서 새로 채우는 일은 없습니다.

말씀하신 '미복원 항목을 검토 대상으로 남기는 테스트'와 같은 취지로, 공개 테스트 세트와 커버리지 리포트를 함께 공개하고 있습니다. 원문에 없는 값을 모델이 새로 만들어 내는 경우를 별도로 플래그하는 기능은 아직 없지만, 좋은 테스트 케이스로 추가할 가치가 있다고 봅니다.

Collapse
 
shuttlewright profile image
Shuttlewright •

제안하신 테스트가 방금 출시되었습니다: Mask가 이제 복원된 텍스트에서 모델이 새로 만들어 낸 토큰과, 원래 토큰이 변경된 경우(대소문자/공백/괄호 변경)를 하이라이트로 표시합니다. 어떤 값도 추측해서 채우지 않습니다. 업무 메일 초안처럼 정확도가 중요한 곳에 바로 써 보실 수 있습니다: shuttlewright-mask.pillar-3a8.work...

Collapse
 
shuttlewright profile image
Shuttlewright •

Tested this against the live restore step so the answer is exact. Restore is a straight token-to-value replace against the map in your tab. If the model invents a token that is not in the map (say [PERSON_9]), it passes through untouched: it stays visible as a bracket token in the restored text, and no value is ever guessed. If the model drops a token, that real value simply does not appear in the reply - again nothing is invented. What it does not do yet is count or flag those two cases separately, which is exactly the check you describe - fair ask, noted for the next revision. Until then: any leftover bracket token after restore is your visible signal that the model drifted from the masked text.