Skip to content

fix(leads): a link ends where its URL characters end - #156

Merged
ralyodio merged 1 commit into
masterfrom
fix/url-boundary-in-drafts
Jul 28, 2026
Merged

ralyodio merged 1 commit into
masterfrom
fix/url-boundary-in-drafts

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

From the production run log, 15:46:

4cornerresources.com: links to https://threatcrush.com/get-whitepaper—download,
                      which the campaign never mentions

The campaign had declared that URL:

pitch_ask: "…download our free whitepaper at https://threatcrush.com/get-whitepaper"

The draft read "…at https://threatcrush.com/get-whitepaper—download takes a minute". The em-dash was prose. The guard's pattern — [^\s)>\]]+, anything up to whitespace — swallowed it and the word after it, then rejected the draft for linking somewhere invented.

The pattern was simply wrong

Non-ASCII can't appear in a URL without percent-encoding, so the dash was never part of the link. Now matching only what RFC 3986 permits, with trailing sentence punctuation stripped rather than just . and ,:

"grab it at …/get-whitepaper—download now"  → …/get-whitepaper
"see https://x.test/a."                     → https://x.test/a
"see (https://x.test/a), then"              → https://x.test/a
"https://x.test/a_b-c~d/e?f=1&g=2#h then"   → unchanged (all legal)

The draft is repaired, not just re-checked

A URL welded to an em-dash is one some mail clients autolink including the dash — a 404 on the single thing the email asked the recipient to click. So a space is inserted and the tidied body is what gets sent. Checking a repaired draft and sending the broken original would be worse than not repairing it.

An invented link is still caught — pinned by a test, since that's the guard's job.

Checks

  • tsc --noEmit clean · 1,049 tests pass (7 new) · build compiles

🤖 Generated with Claude Code

The live draft read "...at https://threatcrush.com/get-whitepaper—download
takes a minute", and the guard extracted the URL as
"https://threatcrush.com/get-whitepaper—download" — matched it against the
campaign, found nothing, and rejected the draft for linking somewhere
invented. The campaign had declared that URL. The em-dash was prose.

Matching "anything up to whitespace" is what did it. Non-ASCII cannot
appear in a URL without being percent-encoded, so the dash was never part
of the link; the pattern now matches only what RFC 3986 permits, and
trailing sentence punctuation is stripped rather than only a full stop or
a comma.

The draft is also repaired rather than merely re-checked. A URL welded to
an em-dash is one some mail clients will autolink including the dash,
which is a 404 on the single thing the email asked the recipient to click
— so a space is inserted, and the tidied body is what gets sent. Checking
a repaired draft and then sending the broken original would have been
worse than not repairing it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@ralyodio
ralyodio merged commit 8e75bf8 into master Jul 28, 2026
8 checks passed
@ralyodio
ralyodio deleted the fix/url-boundary-in-drafts branch July 28, 2026 16:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant