Skip to content

Security: fix authenticated path traversal (arbitrary file write) in Share and Notification plugins#2163

Open
jessedegans wants to merge 2 commits into
GSConnect:mainfrom
jessedegans:fix-share-path-traversal
Open

Security: fix authenticated path traversal (arbitrary file write) in Share and Notification plugins#2163
jessedegans wants to merge 2 commits into
GSConnect:mainfrom
jessedegans:fix-share-path-traversal

Conversation

@jessedegans

@jessedegans jessedegans commented Jun 1, 2026

Copy link
Copy Markdown

I think there's a path traversal in the Share plugin's file receive, current as of v72, and the same pattern in the Notification plugin's icon cache.

When a file comes in, _getFile() in src/service/plugins/share.js builds the save path directly from the remote-supplied filename:

const basepath = GLib.build_filenamev([dirpath, filename]);

filename is packet.body.filename from the incoming kdeconnect.share.request, and build_filenamev doesn't normalize .., so a paired device can send something like filename: "../../.config/autostart/x.desktop" and the file gets written outside the download directory. It's made worse by packet.body.open (around line 220), which auto-launches the received file, so a malicious or compromised paired device can drop a file at an arbitrary path and have it opened automatically.

The same issue occurs in notification.js _downloadIcon, which uses packet.body.payloadHash directly as the cache filename (around line 471), so a crafted payloadHash can traverse out of the cache dir.

It does require a paired device, so it isn't unauthenticated, but pairing is meant to gate "can send me files", not "can write anywhere in my home directory and add autostart entries".

Repro:

  1. Pair a device.
  2. Send a share request with filename set to ../evil (or an autostart .desktop path) plus a payload.
  3. The file lands outside ~/Downloads.

Affected: v72, and as far as I can tell every prior version, since the logic has been the same.

This PR reduces both names to their basename before joining, which blocks .. and absolute paths.

The Share plugin built the save path directly from packet.body.filename
without sanitization, so a paired device could send '../' or an absolute
path and write outside the download directory (made worse by the 'open'
flag, which auto-launches the received file). Reduce the filename to a
single basename before building the destination path.
@jessedegans jessedegans changed the title Sanitize remote-supplied filename in Share plugin (path traversal) Fix authenticated path traversal in Share plugin (file receive) Jun 1, 2026
@jessedegans jessedegans changed the title Fix authenticated path traversal in Share plugin (file receive) Security: fix authenticated path traversal (arbitrary file write) in Share plugin Jun 1, 2026
_downloadIcon used packet.body.payloadHash directly as the cache filename,
the same untrusted-filename-as-path issue as the Share plugin. Collapse it
to a basename so a crafted payloadHash can't traverse out of the cache dir.
@jessedegans jessedegans changed the title Security: fix authenticated path traversal (arbitrary file write) in Share plugin Security: fix authenticated path traversal (arbitrary file write) in Share and Notification plugins Jun 1, 2026
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.

1 participant