Skip to content

ExecutionUser activityPersistence

Snap and Flatpak Artifacts: Linux Sandboxed App Forensics

Snap and Flatpak evidence on Linux: snapd state.json change history, sideloaded snaps, Flatpak installations and remotes, and per-app data directories.

Location
/var/lib/snapd/, /snap/, ~/snap/; /var/lib/flatpak/, ~/.local/share/flatpak/, ~/.var/app/
Proves
Which sandboxed applications were installed, refreshed or removed, from which store or remote, whether any were sideloaded, and where each app kept its user data
Timestamps
RFC 3339 times with zone in snapd state.json; journal UTC entries for Flatpak history; directory and deployment file times
Access
root for /var/lib/snapd/state.json; world-readable Flatpak system installation; user data owned by each user
Retention
Installed apps and data persist until removal; snapd prunes old change records; Flatpak history lasts as long as the journal
Collection
UAC, Velociraptor, cp -a, tar
  • snapCLI · built into Linux
  • flatpakCLI · built into Linux
  • jqCLI · open source
  • journalctlCLI · built into Linux
  • findCLI · built into Linux

What it is

Snap (Canonical, default on Ubuntu) and Flatpak (default on Fedora Workstation and widely available on Debian, SUSE and Arch) install applications outside the distribution's package manager. Their installs, updates and removals do not appear in dpkg or RPM logs, and each app keeps its user data in its own directory, not in the usual ~/.config and ~/.mozilla paths.

Missing these locations is a common reason for "no evidence found": on Ubuntu desktops, Firefox, Chromium, Thunderbird and many chat clients are snaps by default.

Where it lives

ItemSnapFlatpak
System state/var/lib/snapd/state.json (JSON, root only)/var/lib/flatpak/ (OSTree repo, app/, runtime/, exports/)
Package files/var/lib/snapd/snaps/<name>_<rev>.snap (SquashFS)/var/lib/flatpak/app/<id>/<arch>/<branch>/<commit>/
Mount points/snap/<name>/<rev>/, /snap/<name>/currentnone; deployed trees
Per-user installnot supported~/.local/share/flatpak/
App system data/var/snap/<name>/<rev>/, /var/snap/<name>/common/none
App user data~/snap/<name>/<rev>/, ~/snap/<name>/common/~/.var/app/<app-id>/{config,data,cache}/
SourcesSnap Store (snapcraft.io), or local fileRemotes: /var/lib/flatpak/repo/config, /etc/flatpak/remotes.d/, ~/.local/share/flatpak/repo/config
Permissionssnap connections; AppArmor profiles in /var/lib/snapd/apparmor/profiles/Overrides: /var/lib/flatpak/overrides/, ~/.local/share/flatpak/overrides/
Servicessystemd units snap.<name>.<app>.service in /etc/systemd/system/none (apps are user-launched)
Logsjournal (snapd unit)journal, read by flatpak history

What it proves

  • Snap installs, refreshes, reverts and removals with start and end times (changes in state.json, snap changes live).
  • Sideloading: snaps installed from a local file get revisions like x1, x2, and --dangerous or --devmode installs skip store signatures and confinement.
  • Flatpak installs, updates and uninstalls, with the remote, ref and commit, from flatpak history journal entries.
  • Which remotes a host trusted. An unfamiliar Flatpak remote or a snap from an unexpected publisher is a supply-chain lead.
  • Where the app kept user data: browser profiles, chat databases and downloads caches under ~/snap/ and ~/.var/app/.
  • It does not record when a user ran an app; use the journal, thumbnails and the app's own data.

Key fields

jq '.changes[] | {id, kind, summary, status, "spawn-time", "ready-time"}' state.json | head -40
jq '.data.snaps | to_entries[] | {name: .key, current: .value.current, type: .value.type,
    devmode: .value.devmode, sequence: [.value.sequence[] | .revision]}' state.json
FieldMeaning
changes[].kindinstall-snap, refresh-snap, remove-snap, revert-snap, auto-refresh
spawn-time, ready-timeStart and completion of the change, RFC 3339 with zone
data.snaps.<name>.sequenceInstalled revisions; x<N> means local, unasserted
devmode, jailmode, classicConfinement flags; classic snaps have full system access
Flatpak history columnsTime, change (deploy install, deploy update, uninstall), application ref, branch, installation, remote, commit

Timestamps

snapd writes RFC 3339 times with a zone offset or Z in state.json. Flatpak history comes from structured journal entries, stored in UTC microseconds. Directories under /var/lib/snapd/snaps/, /var/lib/flatpak/app/ and ~/.var/app/<id>/ carry creation times close to the first install or first launch; the per-user data directory is created at first launch, which is useful when the history is gone.

Retention

snapd prunes completed changes after a while, so state.json keeps recent history only (hours to days on busy systems); older activity survives in the journal. snapd keeps a small number of revisions of each snap (refresh.retain, 2 by default on current releases), so older .snap files and ~/snap/<name>/<rev>/ directories may still be there. Flatpak keeps no history file of its own; flatpak history is empty once journal retention has passed. Uninstalling a Flatpak leaves ~/.var/app/<id>/ in place unless the user passes --delete-data.

Collection

tar -C /mnt/evidence -cpf /cases/2026-017/sandboxed.tar var/lib/snapd/state.json var/lib/snapd/apparmor \
  var/snap etc/systemd/system/snap.* var/lib/flatpak/repo/config var/lib/flatpak/overrides \
  etc/flatpak home/*/snap home/*/.var/app home/*/.local/share/flatpak/repo/config 2>/dev/null
ls -la --time-style=full-iso /mnt/evidence/var/lib/snapd/snaps/ /mnt/evidence/var/lib/flatpak/app/ > inventory.txt

# Live
snap list --all; snap changes; flatpak list --columns=all; flatpak history; flatpak remotes -d

UAC runs snap list and flatpak list in live response and collects the journal. The .snap and OSTree payloads are large; hash them and collect selectively.

Parsing

S=/cases/2026-017/var/lib/snapd/state.json
jq -r '.changes[] | [."spawn-time", .kind, .status, .summary] | @tsv' "$S" | sort
jq -r '.data.snaps | to_entries[] | select(any(.value.sequence[]; (.revision|tostring)|startswith("x"))) | .key' "$S"

# Flatpak history offline, from the journal
journalctl -D /cases/2026-017/var/log/journal -t flatpak -t flatpak-system-helper -o short-iso-precise
journalctl -D /cases/2026-017/var/log/journal -u snapd -o short-iso-precise | grep -iE 'install|remove|refresh'

On a live system, flatpak history --columns=time,change,application,remote,commit formats the journal entries directly.

Investigator tips

  • Browser, messaging and mail evidence in snaps and Flatpaks lives under ~/snap/<name>/common/ or ~/.var/app/<id>/; point your browser profile parsers there.
  • Snap services run as root through systemd units named snap.<name>.<app>.service. A service from a local x1 revision is persistence that bypassed the store.
  • Classic confinement and --devmode remove the sandbox. Treat such snaps like any unpackaged binary.
  • An extra Flatpak remote added with flatpak remote-add (visible in repo/config) can deliver malicious updates to already-installed apps; check its URL and GPG key.
  • Removal of a snap leaves an automatic snapshot of its data in /var/lib/snapd/snapshots/ for about 31 days on recent snapd versions, which can hold data the user thought was gone.

See also