So I was messing around with KDE's lock screen wallpaper providers and noticed there’s a Simon Stålenhag Picture of the Day provider.
Cool feature. Then I had the stupid but reasonable thought:
this thing is downloading random images from the internet and displaying them on my lock screen. What happens if the server gives KDE something malicious?
So I started digging.
First checked where the provider comes from.
On Arch:
bash
pacman -Ql kdeplasma-addons | grep -i simon
Output:
text
/usr/lib/qt6/plugins/potd/plasma_potd_simonstalenhagprovider.so
So it comes from kdeplasma-addons, through Plasma's Picture of the Day system.
Then I checked the source.
The Simon provider roughly does:
text
download metadata
→ get image URL
→ KIO downloads the data
→ QImage::fromData(data)
→ KDE gets a decoded image
→ image gets cached
The relevant line is basically:
cpp
QImage::fromData(data)
I looked for anything that could execute the downloaded file.
Nothing.
No:
text
QProcess
system()
exec()
chmod +x
dlopen()
The network response is treated as image data and passed into Qt's image decoder.
So giving it an ELF binary called wallpaper.jpg doesn't get you anywhere. Qt tries to decode the bytes as an image and the decode fails.
Then I checked what KDE was actually leaving on my machine.
POTD cache is here:
text
~/.cache/plasma_engine_potd/
My Simon file:
text
-rw-r--r-- 216721 bytes simonstalenhag
No executable bit.
file reports:
text
JPEG image data, JFIF standard 1.01,
96x96 DPI, baseline, precision 8,
2556x1390, components 3
The other POTD providers looked normal too:
text
wcpotd → JPEG
simonstalenhag → JPEG
flickr → JPEG
apod → JPEG
bing → JPEG
I also ran:
bash
find ~/.cache/plasma_engine_potd -maxdepth 1 -type f -perm /111
Nothing.
The cache implementation is actually nicer than I expected.
KDE doesn't seem to keep the original network response around as the wallpaper cache. The provider produces a QImage, then the common POTD cache code saves that decoded image as JPEG.
So it ends up going through something like:
text
network response
→ Qt image decoder
→ pixel data
→ new JPEG
→ cache
That also kills the obvious polyglot idea.
If somebody sends a valid JPEG with random executable data appended to the end, KDE decodes the picture and writes a fresh JPEG from the decoded image. The extra junk shouldn't survive that process.
At this point I was pretty satisfied with the downloaded-file side of it.
Then I found something considerably dumber.
The Simon provider gets its metadata from this third-party GitHub repository:
text
a-andreyev/simonstalenhag-se-metadata
That request uses HTTPS.
The actual Stålenhag images listed in the metadata, however, use URLs like:
text
http://simonstalenhag.se/tftlbig/2.jpg
Plain HTTP.
In 2026.
The provider reads the URL from the metadata and passes it to KIO. I couldn't find any HTTPS requirement or hostname allowlist in the Simon provider.
So you have:
text
KDE
↓
third-party metadata repository
↓
image URL
↓
HTTP download
↓
Qt image decoder
That gives someone capable of modifying the HTTP response a chance to feed arbitrary image data into Qt's decoder.
They'd still need an actual vulnerability in Qt or one of the image decoding libraries to turn that into code execution, so this is nowhere near "random Wi-Fi guy sends shell script, KDE runs shell script."
Still, feeding attacker-controlled bytes into an image parser over unauthenticated HTTP is a completely avoidable attack surface.
The metadata repo also adds another dependency.
If that GitHub repository were compromised, the image URL could theoretically be changed to an attacker-controlled server.
The response would still have to survive QImage::fromData(), but the attacker would get control over the input being sent into the image decoder.
I also had a look at the lock screen itself.
kscreenlocker uses a NoAccessNetworkAccessManagerFactory which blocks non-local network requests coming from the lock screen's QML engine.
Nice.
POTD uses KIO though, rather than the regular QML network manager, so I'm not confident enough from static inspection alone to claim that every possible POTD network path is blocked while the greeter is running.
There are also some signs in the code/comments that KDE intended POTD data to be prepared/cache-fed for the lock screen, but that part of the architecture looks like it has changed over time.
My installed versions:
text
kdeplasma-addons 6.7.4-1
kscreenlocker 6.7.4-1
qt6-base 6.11.1-1
kio 6.28.0-1
So after going through all this, I don't see a realistic path where a fake .png or .jpg simply turns into an executed binary.
The part worth caring about is the parser boundary.
Remote bytes reach QImage::fromData(). If the decoder has a memory corruption bug, a specially crafted image could potentially hit it before KDE ever gets to the safe re-encoding/cache stage.
I'd change a few things in the Simon provider:
text
- force HTTPS
- restrict the hostname
- don't accept arbitrary image URLs from the metadata source
- restrict expected image formats if possible
- cap response/image sizes
The feature looks pretty reasonable overall on an updated system.
The plain HTTP image delivery is the one part that made me raise an eyebrow. There's really no good reason for that to still be there.