fix(security): link warning no longer bypassed by a sentence or shared hosting (#335) #360

Merged
jared merged 2 commits from fix/link-safety-bypasses into lotus 2026-10-16 19:59:20 -04:00
Owner

Fixes #335.

Bypass 1: a sentence around the trusted name. Any whitespace in the link text disabled the check, so "Log in at chat.lotusguild.org" → evil.example wasn't flagged.

  • hostsFromText now scans each word for host-shaped tokens, and the link is flagged if any named host is a different site.
  • Bare file names (main.py, report.pdf) and version numbers are skipped inside sentences, so ordinary links aren't flagged.

Bypass 2: shared hosting. Sites on a shared hosting domain counted as one site: alice.github.io vs evil.github.io, *.pages.dev, netlify.app, vercel.app and so on.

  • registrableDomain now treats a curated list of them as public suffixes (longest match first, including s3.amazonaws.com).
  • It's curated rather than the full Public Suffix List, to stay inside the bundle budget.

Verified with 2 new unit tests, and headless on real messages:

link text → destination flagged
"Log in at chat.lotusguild.org" → evil.example ✅ yes
"chat.lotusguild.org (official)" → evil.example ✅ yes
"lotusguild.pages.dev" → evil.pages.dev ✅ yes
"alice.github.io" → evil.github.io ✅ yes
"Log in at chat.lotusguild.org" → chat.lotusguild.org/login no
"see main.py and report.pdf" → github.com no
"release v1.2.3 notes" → github.com no
"click here" → evil.example no

tsc clean · unit tests pass · ESLint/Prettier clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5

Fixes #335. **Bypass 1: a sentence around the trusted name.** Any whitespace in the link text disabled the check, so "Log in at chat.lotusguild.org" → `evil.example` wasn't flagged. - `hostsFromText` now scans each word for host-shaped tokens, and the link is flagged if **any** named host is a different site. - Bare file names (`main.py`, `report.pdf`) and version numbers are skipped inside sentences, so ordinary links aren't flagged. **Bypass 2: shared hosting.** Sites on a shared hosting domain counted as one site: `alice.github.io` vs `evil.github.io`, `*.pages.dev`, `netlify.app`, `vercel.app` and so on. - `registrableDomain` now treats a curated list of them as public suffixes (longest match first, including `s3.amazonaws.com`). - It's curated rather than the full Public Suffix List, to stay inside the bundle budget. **Verified** with 2 new unit tests, and headless on real messages: | link text → destination | flagged | |---|---| | "Log in at chat.lotusguild.org" → evil.example | ✅ yes | | "chat.lotusguild.org (official)" → evil.example | ✅ yes | | "lotusguild.pages.dev" → evil.pages.dev | ✅ yes | | "alice.github.io" → evil.github.io | ✅ yes | | "Log in at chat.lotusguild.org" → chat.lotusguild.org/login | no | | "see main.py and report.pdf" → github.com | no | | "release v1.2.3 notes" → github.com | no | | "click here" → evil.example | no | `tsc` clean · unit tests pass · ESLint/Prettier clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
jared added 1 commit 2026-10-16 18:56:04 -04:00
fix(security): link warning no longer bypassed by a sentence or shared hosting (#335)
CI / Build & Quality Checks (pull_request) Successful in 1m47s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 7s
CI / Playwright smoke (e2e) (pull_request) Failing after 11m30s
a8a7e639a9
Two easy bypasses of the "this link goes somewhere else" check:

- Any whitespace in the link text disabled it, so "Log in at
  chat.lotusguild.org" → evil.example wasn't flagged. hostsFromText now
  scans each word for host-shaped tokens; a link is flagged if any named
  host is a different site. Bare file names (main.py, report.pdf) and
  version numbers are skipped inside sentences so ordinary links aren't
  flagged.
- Shared-hosting suffixes counted as one site (alice.github.io vs
  evil.github.io, *.pages.dev, netlify.app, vercel.app, …).
  registrableDomain now treats a curated list of them as public suffixes
  (longest match, incl. s3.amazonaws.com). Curated rather than the full
  PSL to stay inside the bundle budget.

Verified with unit tests and headless on real messages: the four bypass
cases are flagged; the honest sentence, file/version text and "click
here" are not.

Fixes #335

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
jared added 1 commit 2026-10-16 19:33:56 -04:00
Merge branch 'lotus' into fix/link-safety-bypasses
CI / Build & Quality Checks (pull_request) Successful in 1m40s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 6s
CI / Playwright smoke (e2e) (pull_request) Successful in 11m25s
47328d6fee
jared merged commit 4b8c3219e9 into lotus 2026-10-16 19:59:20 -04:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: LotusGuild/cinny#360