Skip to content

fix(web): stop extractUrls treating email addresses as URLs#1187

Open
abhay-codes07 wants to merge 1 commit into
supermemoryai:mainfrom
abhay-codes07:fix/extract-urls-email-false-positives
Open

fix(web): stop extractUrls treating email addresses as URLs#1187
abhay-codes07 wants to merge 1 commit into
supermemoryai:mainfrom
abhay-codes07:fix/extract-urls-email-false-positives

Conversation

@abhay-codes07

@abhay-codes07 abhay-codes07 commented Jul 2, 2026

Copy link
Copy Markdown

What

extractUrls in apps/web/lib/url-helpers.ts treats email addresses as URLs. URL_TOKEN_REGEX has no left boundary, so for

email me at john.doe@example.com

it extracts two bogus URLs: https://john.doe and https://example.com.

This is user-visible: the add-document note view (components/add-document/note.tsx) shows a "N links detected — save each as its own memory?" banner when 2+ URLs are detected, so a note containing a single email address triggers a bulk-import offer of garbage links.

There's a second defect in the same function: the dedupe key lowercases the entire URL, so https://example.com/Page and https://example.com/page — distinct, case-sensitive resources — are collapsed and one is silently dropped.

How

  • Switched from match to matchAll and inspect the characters adjacent to each candidate: a token ending at @ is an email local part, a token starting right after @ is the mail domain, and a token beginning mid-word (e.g. after _, which the hostname charset can't include) isn't a standalone URL. All are skipped.
  • The dedupe key is now built from the parsed URL (origin + pathname + search + hash), so scheme and host compare case-insensitively — which the URL parser normalizes anyway — while path, query, and hash stay case-sensitive. Trailing-slash-only variants still count as duplicates, as before.

No API change: same signature, same {urls, duplicates} result shape.

Testing

  • New apps/web/lib/extract-urls.test.ts (bun:test, same setup as the other lib/*.test.ts files): emails alone, emails mixed with real URLs, multiple emails, markdown/angle-bracket links, scheme-less URLs, trailing punctuation, case/slash dedupe, and case-sensitive paths kept distinct.
  • Verified the tests catch the bugs: 4 of 9 fail against the previous implementation; the other 5 pin existing behavior and pass on both.
  • Full web lib suite passes (23 tests); biome check clean.

Note: the test lives in its own file rather than url-helpers.test.ts because #1182 (open) adds that file for the YouTube-detection fix — this way the two PRs merge cleanly in either order.

cc @MaheshtheDev


Session Details

  • Session: View Session
  • Requested by: Unknown
  • Address comments on this PR. Add (aside) to your comment to have me ignore it.

URL_TOKEN_REGEX has no left boundary, so extractUrls matched
domain-shaped tokens inside email addresses: "john.doe@example.com"
produced two bogus URLs, https://john.doe and https://example.com.
Since the add-document note view offers a bulk "N links detected -
save each as its own memory?" banner at two or more detected URLs, a
note containing a single email address triggered an import offer of
garbage links.

Switch to matchAll and inspect the characters adjacent to each match:
tokens ending at "@" (email local part), starting after "@" (mail
domain), or beginning mid-token are skipped.

Also fix the dedupe key, which lowercased the whole URL and dropped
distinct case-sensitive paths (https://example.com/Page vs /page).
The key is now built from the parsed URL, so scheme and host compare
case-insensitively while path, query, and hash stay case-sensitive.

Add regression tests; four of the nine fail against the previous
implementation.
Copilot AI review requested due to automatic review settings July 2, 2026 03:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@vorflux vorflux Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Reviewed — found 1 issue(s). I reviewed the extractUrls change in apps/web/lib/url-helpers.ts and the added regression coverage in apps/web/lib/extract-urls.test.ts. The new email guard still misses common email local-part formats, so some email addresses can still produce bogus extracted URLs.

Findings

apps/web/lib/url-helpers.ts

  1. extractUrls only checks characters immediately adjacent to a matched domain token, which misses email local-parts containing separators such as +, _, -, or % before @.

Verdict

⚠️ Changes requested. The fix does not fully eliminate email-address false positives for common valid email formats.


Review with Vorflux

// local part, one starting right after "@" is the mail domain. Also
// skip matches that begin mid-token (e.g. after "_", which the
// hostname charset can't include) — those aren't standalone URLs.
if (after === "@" || before === "@" || /[\w.-]/.test(before)) continue

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filter still misses common valid email local-parts that contain separators before the @. For example, first.last+tag@example.com can match first.last because the candidate ends before +, so neither adjacent character is @. Consider skipping the surrounding non-whitespace token whenever it contains @, or otherwise detecting email tokens before URL matching.

@vorflux

vorflux Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Testing

The testing subagent classified the change as internal URL-extraction logic only, with no UI, mobile, API, schema, or integration surface. It ran the focused extractUrls test file and formatting/lint check for the touched files; both passed.

Commands run:

bun test apps/web/lib/extract-urls.test.ts
bunx biome ci apps/web/lib/url-helpers.ts apps/web/lib/extract-urls.test.ts

Result:

bun test apps/web/lib/extract-urls.test.ts
9 pass
0 fail
13 expect() calls
Ran 9 tests across 1 file.

bunx biome ci apps/web/lib/url-helpers.ts apps/web/lib/extract-urls.test.ts
Checked 2 files. No fixes applied.

Verdict

Passed. Focused unit coverage and Biome checks passed for the changed URL helper and regression tests.

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.

2 participants