Files
2026-11-04 14:29:22 -06:00

6.6 KiB

Security model

LiveWall is a wallpaper app that can run third-party code. This page states plainly what that means, what the app does about it, and what it cannot do.

The blunt version

A plugin is a .NET assembly loaded into LiveWall's own process, with LiveWall's rights. There is no sandbox, no separate account, no permission-checking kernel layer. A plugin can:

  • read and write any file your user account can reach (documents, browser profiles, keys);
  • open network connections and upload whatever it found;
  • change or delete your LiveWall settings and wallpapers;
  • register global hotkeys and log keystrokes of its own (as any process can);
  • crash LiveWall (only the plugin's own failures are contained — see below).

The permission list is therefore informed consent, not a security boundary. LiveWall enforces it where enforcement makes sense (it will not register an overlay without DesktopOverlay), and the warning dialog shows exactly what a plugin asked for, but a hostile plugin that lies in its manifest is only limited by your user account.

Install plugins the way you install any other program: from a source you trust, ideally with a reviewable repository.

What LiveWall actually does

The warning before anything runs

Two gates, both modal, both requiring an explicit acknowledgement:

  1. The plugin system itself. Turning on Enable the plugin system shows a full-screen-format warning: third-party code, unverified plugins may cause harm to your computer, nothing is sandboxed, only proceed with sources you trust. The checkbox must be ticked before Enable plugins becomes clickable. ConsentGiven is stored, so this is asked once per installation.

  2. Every single plugin. Enabling a plugin shows a card with name, author, version, id, folder, its SHA-256 hash, a verified/unverified verdict, and the full permission list expanded into human sentences. Again the acknowledgement must be ticked first.

The same warning banner stays visible at the top of the Plugins tab permanently — the user is never more than one click from the reminder.

Off by default

Plugins.Enabled is false in a fresh configuration, and AllowUnverified is false as well. With both off, nothing in %APPDATA%\LiveWall\plugins is loaded at all; the folder is only scanned so the list can be shown.

Hash-pinned trust

  • Every plugin's entry assembly is hashed (SHA-256) at load time.
  • When the user accepts a warning, that exact hash is stored in %APPDATA%\LiveWall\plugin-trust.json as { "<plugin id>": "<sha256>" }, and mirrored into settings.json (Plugins.Plugins[] { Enabled, ApprovedHash }).
  • If the DLL changes — an update, but also the first sign of tampering — the hash no longer matches, the plugin is unverified again, and the warning reappears. There is no way to enable a mismatched plugin silently: the Enable button path always shows the dialog.
  • Forget trust (in the row, visible for verified plugins) removes the stored hash; the next enable asks again.
  • A manifest may also carry a checksum; when present it must match the assembly or the plugin is rejected outright (ChecksumMismatch), which lets a publisher pin the exact build they shipped.

Failing safely

  • Initialize, every command, page build, filter pass, renderer call, hotkey action and event handler is wrapped: exceptions are logged with the plugin id and the offending feature stops being used. The plugin shows as Failed with the message.
  • A plugin that fails to load is never retried in a loop.
  • A crashing native plugin can still take the process down (as can any in-process code). LiveWall logs each step of loading so the culprit is identifiable afterwards.
  • LiveWall never executes a plugin it has not been explicitly told to enable — there is no auto-load from a zip, download, or command line.

Isolation of the file system

  • Plugin data goes to %APPDATA%\LiveWall\plugin-data\<id>\ (IPluginStorage). Folder names are sanitised from the plugin id, so ../../Windows cannot be used to escape.
  • The plugin folder itself is %APPDATA%\LiveWall\plugins\<folder>\. Nothing else in the app's own data folder is exposed through the SDK except Storage.PathFor, which is confined to the plugin's data folder.

Assembly loading

Plugins are loaded into a collectible AssemblyLoadContext that has LiveWall.Sdk shared with the host. This means:

  • two plugins can ship different versions of the same helper library without colliding;
  • unloading actually releases the assembly, so a fixed plugin can be retried after Rescan;
  • a plugin cannot accidentally shadow LiveWall.Sdk and hand back the wrong interface type.

What LiveWall does not do

  • It does not sandbox, virtualise or restrict the plugin's file/network/process access.
  • It does not scan plugins for malware, and does not transmit hashes anywhere.
  • It does not "verify" against a public signature: verified on this machine means "this exact file is the one you approved", not "this file is trustworthy".
  • It does not protect against a plugin that persists (auto-start entry, scheduled task) — check shell:startup, HKCU\Software\Microsoft\Windows\CurrentVersion\Run and Task Scheduler if you distrust something you ran.
  • It cannot undo what a plugin already did to your files. Back up first if you are experimenting.

Advice for users

  1. Turn the plugin system on only when you have a plugin you actually want.
  2. Read the permission list. FileSystem + Network together is "it can upload my files" — that had better be a plugin you trust.
  3. Prefer plugins whose source you can read. A DLL alone is a black box.
  4. If the hash of a plugin you have been using changes after an update, that is expected — but it is also exactly what tampering looks like, so treat the new warning as real.
  5. To be sure a plugin is gone: Disable it, delete its folder, and delete %APPDATA%\LiveWall\plugin-data\<id>.

Advice for developers

  • Declare all permissions you use, and nothing else. Over-declaring trains users to click through.
  • Never call SetWallpaper in a loop; it reloads media.
  • Don't write outside context.Storage.DataFolder. If you need a user-chosen location, ask for it explicitly and remember it.
  • Long work belongs on the thread pool; the UI thread stalls the wallpaper and your own overlay.
  • Log through context.Log, not to your own file, so everything is in one place for support.
  • Treat the returned IDisposables and ShutdownToken seriously: unload happens while the user is watching, and a plugin that leaves a timer running keeps the load context alive.