# 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 `{ "": "" }`, 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\\` (`IPluginStorage`). Folder names are sanitised from the plugin id, so `../../Windows` cannot be used to escape. * The plugin folder itself is `%APPDATA%\LiveWall\plugins\\`. 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\`. ## 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 `IDisposable`s and `ShutdownToken` seriously: unload happens while the user is watching, and a plugin that leaves a timer running keeps the load context alive.