Backups in 2026: revisit restic, BorgBackup and Kopia before you trust another backup job

Picture a GST and accounting services firm in Surat with fourteen branches (an invented example, not a real client). Each branch has a small Linux file server for scanned invoices and client folders, the head office runs a PostgreSQL database for its billing and compliance tracker, and about forty staff laptops hold working copies of return files. The current “backup” is a nightly rsync from every branch to a NAS at head office, plus a weekly tar to a USB disk. In the March filing rush a laptop picked up ransomware, encrypted the NAS share it had mounted read-write, and the next rsync copied the encrypted files over the good ones at three branches. The USB disk was eleven days old. Three engineers now propose a proper design. One wants restic writing to the S3-compatible bucket they already run. A second wants BorgBackup over SSH to a hardened backup VM. A third wants Kopia, because KopiaUI looks friendly enough for staff laptops.

All three are open-source, deduplicating, client-side encrypted backup programs that store snapshots in a repository you own. They are not sync tools, not filesystem snapshot tools and not database backup tools, though each one sits next to those. This post compares restic, BorgBackup (Borg) and Kopia for servers and developer machines: repository format, encryption and key handling, compression, storage backends, append-only and ransomware resistance, pruning, verification, licences and security. Facts come from release notes, official documentation, source repositories, licence files and CVE records, checked on 13 October 2026. The drill near the end is my own run on this Linux box.

The short version

  • A backup the infected machine can delete is only a copy. Decide first who can delete or overwrite backup data, then pick a tool. Sync copies damage forward; a versioned, deduplicated repository keeps yesterday’s good files.
  • restic 0.19.1 (5 July 2026, 1:43 PM IST) is the current release. It is a single Go binary (BSD 2-Clause) with zstd compression in repository format v2 and many native backends. Append-only comes from rest-server --append-only or rclone serve restic --append-only, not from restic itself.
  • BorgBackup 1.4.5 (19 July 2026, 4:06 AM IST) is the current stable release; the 1.2 line has ended. Borg 1.x (BSD 3-Clause) talks to local paths or to borg serve over SSH, where append-only is a server-side setting. Borg 2.0.0b25 (28 September 2026, 4:29 AM IST) is still a beta that its README says not to use for production.
  • Kopia 0.23.1 (16 June 2026, 6:57 AM IST) is the current release. It is Go (Apache 2.0) with a CLI, a desktop UI, a repository server and S3 object lock support. Compression is off by default, and space from deleted snapshots returns only over full maintenance cycles.
  • Security in 2026: Kopia 0.23.0 fixed a critical unauthenticated remote code execution (CVE-2026-45695) for servers started without a password. Borg 1.4.5 fixed a low-severity extract issue (GHSA-gfp8-w835-v44j). I found no CVE for restic itself; two 2026 rclone CVEs affect rclone serve restic.
  • In my drill on one VM, all three tools backed up a 402.7 MiB dataset, restored 2,996 of 2,996 files with matching hashes and timestamps, and caught a flipped byte in a full data check. restic check and a Kopia snapshot verify without file reads both missed it.

Where things stand on 13 October 2026

Dates are from each project’s GitHub release page; times are converted from UTC to IST. Licences are from the LICENSE files at the tagged release.

Project

Release

Date (IST)

Notes

Licence

restic

0.19.1

5 July 2026, 1:43 PM

Current release; bug fixes on top of 0.19.0 (mount, SFTP on Windows servers, excludes)

BSD 2-Clause

restic

0.19.0

9 June 2026, 10:36 PM

zstd fastest/better levels, check by snapshot filter, prune repacks small packs by default, faster index loading, restore ownership by name

BSD 2-Clause

restic

0.18.1

21 September 2025, 11:54 PM

Bug fixes on 0.18

BSD 2-Clause

restic

0.18.0

28 March 2025, 1:04 AM

Mitigation for an attack on the content-defined chunker; experimental S3 cold storage

BSD 2-Clause

restic rest-server

0.14.0

1 June 2025, 2:02 AM

Companion REST backend with --append-only and --private-repos

BSD 2-Clause

BorgBackup

1.4.5

19 July 2026, 4:06 AM

Current stable; CVE-2026-62268 fix; “related repositories”; --quick-stats

BSD 3-Clause

BorgBackup

1.4.4

19 March 2026, 1:48 PM

Fixes on 1.4; Linux binaries built with FUSE support

BSD 3-Clause

BorgBackup

1.2.9

5 August 2025, 6:52 AM

Release notes: “likely the final 1.2.x release”; migrate to 1.4

BSD 3-Clause

BorgBackup

2.0.0b25

28 September 2026, 4:29 AM

Beta; breaking changes again (new repos needed for b25)

BSD 3-Clause

BorgBackup

2.0.0b22

22 July 2026, 6:13 PM

Beta carrying the CVE-2026-62268 fix

BSD 3-Clause

Kopia

0.23.1

16 June 2026, 6:57 AM

Current release; fixes a rare race that “might lead to a data loss”, upgrade recommended

Apache 2.0

Kopia

0.23.0

12 May 2026, 5:38 AM

Breaking: insecure unauthenticated server only on loopback (CVE-2026-45695 fix); LZ4 removed

Apache 2.0

Kopia

0.22.3

2 December 2025, 12:07 PM

Last release affected by CVE-2026-45695

Apache 2.0

Kopia

0.22.0

18 November 2025, 5:58 AM

Quick maintenance enabled by default on repository creation; maintenance statistics

Apache 2.0

rclone

v1.75.2

9 October 2026, 4:33 PM

Optional backend bridge for restic and Kopia; serve restic CVE fixes in 1.74.4 and 1.75.0

MIT

Packaging note: restic signs SHA256SUMS with a GPG key whose fingerprint is in its install docs. Borg signs the borg-linux-glibc231-x86_64 binary with Thomas Waldmann’s GPG key, while the -gh binaries built on GitHub carry build attestations instead. Kopia signs checksums.txt with its “Kopia Builder” key. All three verified cleanly in my drill. Borg’s 1.4.5 .asc was made on 31 July 2026, twelve days after the release, so do not assume a signature exists the hour a release appears.

Timeline

Date (IST)

Event

9 July 2013

jborg/attic repository created; Attic by Jonas Borgström is the code Borg later forks

27 April 2014

restic/restic repository created (BSD 2-Clause, Alexander Neumann)

13 May 2015

borgbackup/borg repository created as a fork of Attic

14 September 2015

restic 0.1.0

20 December 2015

kopia/kopia repository created

5 March 2016

Borg 1.0.0

10 May 2019

First Kopia release on GitHub (v0.3.0-pre2)

22 February 2022

Borg 1.2.0; space is freed only by an explicit borg compact from 1.2 onwards

8 August 2022

Borg 2.0.0b1 (first Borg 2 beta, date from the changelog)

25 August 2022

restic 0.14.0: repository format v2 with compression

30 August 2023

CVE-2023-36811 (Borg archive spoofing) published; fixed in Borg 1.2.5 and 1.2.6 with an upgrade procedure

3 July 2024

Borg 1.4.0, “a refreshed 1.2”

28 March 2025

restic 0.18.0 with a chunker attack mitigation

6 May and 23 May 2025

Borg 2.0.0b16 removes append-only remnants; 2.0.0b17 adds BORG_REPO_PERMISSIONS (no-delete, write-only, read-only)

5 August 2025

Borg 1.2.9, likely the final 1.2.x

13 May 2026

Kopia advisory GHSA-2q4c-3mrw-63c3 (later CVE-2026-45695) published, one day after 0.23.0

9 June / 5 July 2026

restic 0.19.0 and 0.19.1

16 June / 19 July 2026

Kopia 0.23.1; Borg 1.4.5

27 August 2026

Borg advisory GHSA-gfp8-w835-v44j published

28 September 2026

Borg 2.0.0b25

Borg users today choose between a mature 1.4 line and a much-changed Borg 2 that is still beta after four years of betas. restic and Kopia are both still on 0.x version numbers, which says more about versioning habits than maturity; both have stable repository formats.

First question: who can delete your backups?

The Surat failure was not about which program copied the files; the machine being protected could destroy the protection. Before comparing tools, write down retention, RPO, RTO, and which credentials can delete or overwrite backup data.

Need

Sync or snapshot alone

Needs a backup repository

Mirror a folder to another disk

rsync, rclone sync

Undo yesterday’s accidental delete

Filesystem snapshots may do

Versioned snapshots with retention

Survive ransomware on a client

Repository the client cannot delete: append-only server, object lock or a pull model

Keep 7 daily, 4 weekly, 12 monthly versions cheaply

Deduplication plus a retention policy

Keep data private on a third-party bucket

Client-side encryption

Prove a restore works

Regular check plus a real restore test

The 3-2-1 habit still holds: three copies, two kinds of storage, one off-site. The off-site copy is only safe if its credentials are not sitting on every branch server.

What these three tools actually are

restic 0.19.1

restic is a single Go binary. A repository is a directory of encrypted files: a config file, keys, snapshots, index and data packs. Files are split with content-defined chunking based on Rabin fingerprints with a per-repository secret polynomial. Files smaller than 512 KiB are not split, and blobs range from 512 KiB to 8 MiB, aiming at about 1 MiB on average, before they are packed into pack files.

Encryption is AES-256 in counter mode with a Poly1305-AES MAC. The repository master key is stored in one or more key files, each encrypted with a key derived from a password using scrypt. restic key add, key list, key remove and key passwd manage several passwords for one repository, which helps when an operations team and a break-glass account both need access. Repository format v2, the default since 0.14.0, adds zstd compression; --compression auto is the default, and 0.19.0 added the fastest and better levels next to max and off.

Native backends listed in the 0.19.1 docs: local, SFTP, REST server, Amazon S3 and S3-compatible stores (MinIO, Wasabi, Alibaba OSS and others), OpenStack Swift, Backblaze B2, Azure Blob Storage and Google Cloud Storage, plus anything rclone supports through rclone: URLs. Retention is restic forget with --keep-last, --keep-daily, --keep-within and similar options, followed by prune (or forget --prune). restic check checks structure; check --read-data reads and verifies every pack, and --read-data-subset=n/t spreads that cost over several runs. restic copy copies snapshots between repositories, which is the simple way to keep a second off-site repository.

Recent changes: 0.19.0 made prune repack small packs by default, let check select snapshots by filter, sped up index loading, and fixed a rare loss of split index entries in old format v1 repositories (repair packs fixes it). 0.18.0 randomised how chunks are assembled into packs, to blunt a published attack on the chunker; the changelog rates the practical risk as low.

BorgBackup 1.4.5 (and the Borg 2 beta)

Borg 1.x is Python with performance-critical parts in C and Cython, and ships standalone binaries so servers need no Python install. A repository is a directory of append-only segment files (500 MiB maximum by default), an index, hints and a config file. The default chunker is buzhash with parameters 19,23,21,4095: 512 KiB minimum, 8 MiB maximum, about 2 MiB target.

Encryption is chosen at borg init and cannot be changed later. The 1.4 docs give a rule of thumb: use repokey with a strong passphrase. repokey and keyfile use AES-CTR-256 with HMAC-SHA256; the -blake2 variants use BLAKE2b-256 for authentication and the chunk ID hash, which can be faster on CPUs without SHA acceleration. authenticated modes detect tampering without encrypting, and none does neither. With repokey the encrypted key lives in the repository; with keyfile it lives on the client, so stealing the repository is not enough. Either way, run borg key export (there is a --paper format) and keep that export away from the repository. Passphrases are stretched with PBKDF2-HMAC-SHA256 according to the security internals page. Compression defaults to lz4; zstd, zlib, lzma, auto (only compress what looks compressible) and obfuscate (pad stored sizes against fingerprinting) are available.

Borg 1.4 reaches remote repositories only through ssh:// URLs with borg serve running on the remote host, so the server needs a compatible Borg too. There is no native S3 backend in 1.4; people who want object storage either sync a Borg repository with rclone (the docs suggest smaller segments for that) or wait for Borg 2. Retention is borg prune with --keep-daily, --keep-weekly and similar, and since 1.2 the space is actually freed only when borg compact runs. borg check verifies repository segments and archive metadata; borg check --verify-data also decrypts and verifies every chunk. 1.4.5 adds “related repositories”, which share deduplication secrets while keeping separate encryption keys.

Borg 2 is a different animal. The b25 changelog lists new commands (repo-create instead of init, repo-list, repo-info), new encryption modes (aes256-ocb, chacha20-poly1305, authenticated-sha256, authenticated-blake3), and storage through borgstore with file, SSH, SFTP, HTTP(S) REST server, rclone and S3/B2 URLs. Archives from 1.x come across with borg transfer, which requires the source to be on 1.2.6 or later with the CVE-2023-36811 upgrade steps done. The master README says Borg 2 is in beta, may break between betas, and should not be used for production backups. Plan on 1.4 and test Borg 2 on the side.

Kopia 0.23.1

Kopia is Go, like restic, and ships a CLI, KopiaUI (a desktop app) and a repository server that clients can talk to instead of holding storage credentials themselves. Files are split by a content-defined splitter (DYNAMIC-4M-BUZHASH by default) and packed into p blobs, with indexes managed by an epoch manager.

Encryption defaults to AES256-GCM-HMAC-SHA256, with CHACHA20-POLY1305-HMAC-SHA256 as the alternative. The password is stretched with scrypt (N=65536, r=8, p=1) according to the encryption docs, and the default content hash is BLAKE2B-256-128. Compression is a per-path or global policy and is off by default: kopia policy show --global on a fresh 0.23.1 repository printed “Compression disabled”, with only metadata compressed using zstd-fastest. Supported compressors include zstd, s2, pgzip, gzip and deflate; LZ4 was removed in 0.23.0. The compression docs include a benchmark table, which is Kopia’s own run on its own sample file. Error correction (--ecc) is marked experimental.

Storage locations in the docs: local or network filesystem, Amazon S3 and S3-compatible stores (with object lock and storage classes), Azure Blob, Backblaze B2, Google Cloud Storage, Google Drive (native support is experimental), WebDAV, SFTP, rclone (experimental, tested with Dropbox, OneDrive and Google Drive) and a Kopia repository server. Retention lives in policies; the global defaults I saw were 10 latest, 48 hourly, 7 daily, 4 weekly, 24 monthly and 3 annual snapshots. kopia snapshot verify checks that snapshot contents exist; add --verify-files-percent=100 to read files back, or use kopia content verify --download-percent=100.

Maintenance is Kopia’s distinctive operational piece. Quick maintenance runs roughly every hour and full maintenance every 24 hours, driven by one designated maintenance owner (user@host). Full maintenance marks unreachable contents, rewrites and deletes packs, and the docs warn that its effects are not immediate: removing unused blobs may take several hours or multiple cycles because of safety rules for concurrent clients. --safety=none speeds this up but is only safe when nothing else is writing.

Feature comparison

Area

restic 0.19.1

Borg 1.4.5

Kopia 0.23.1

Language and packaging

Go, single binary

Python + C, standalone PyInstaller binaries or pip

Go, single binary, KopiaUI, repository server

Chunking

Rabin CDC, 512 KiB to 8 MiB, ~1 MiB average

buzhash, 512 KiB to 8 MiB, ~2 MiB target

buzhash splitter, DYNAMIC-4M-BUZHASH default

Encryption

AES-256-CTR + Poly1305-AES, always on

Chosen at init: AES-CTR-256 + HMAC-SHA256 or BLAKE2b, authenticated-only, or none

AES256-GCM-HMAC-SHA256 (default) or ChaCha20-Poly1305, always on

Password stretching

scrypt

PBKDF2-HMAC-SHA256

scrypt

Several passwords per repo

Yes (restic key add)

No; one passphrase per key, export the key

One repository password; per-user passwords via repository server

Compression default

zstd auto (repo v2)

lz4

Off; enable via policy

Parallelism

Multi-threaded

Single-threaded per borg create

Multi-threaded

Remote access

Many native backends + rclone

borg serve over SSH only

Many native backends + rclone + repository server

Copy to second repo

restic copy

Separate repo, or sync the repo files

kopia repository sync-to

Mount snapshots

restic mount (FUSE)

borg mount (FUSE)

kopia mount

Key handling in practice

Lose the password (and for Borg, the key) and the data is gone. That is the point of client-side encryption, and a common way small teams lose backups. For the Surat firm:

  • Keep repository passwords in a secrets manager, not in a script on the branch server; the Vault and OpenBao post covers the options. restic and Borg can fetch a password by command (RESTIC_PASSWORD_COMMAND, BORG_PASSCOMMAND); Kopia reads KOPIA_PASSWORD or a keyring.
  • For Borg, export the repository key once with borg key export and store it with the passphrase in two places, at least one offline.
  • For restic, add a second key for a break-glass account with restic key add, and test it.
  • For Kopia staff laptops, prefer a repository server so laptops hold a per-user server password, not the bucket’s access key.

Backends, S3 targets and where the bytes live

Backend

restic

Borg 1.4

Kopia

Local disk or NAS mount

Yes

Yes

Yes

SFTP

Yes

No (uses borg serve over SSH instead)

Yes

SSH with server-side process

No

borg serve (needs Borg on server)

No (repository server is HTTPS)

Own REST server

rest-server

Borg 2 only (borgstore REST)

Kopia repository server

S3 and S3-compatible

Native

Borg 2 only

Native, with object lock

B2, Azure, GCS

Native

Borg 2: S3/B2 only

Native

rclone

Yes

Borg 2 only

Yes (experimental)

restic and Kopia can write straight to the Surat firm’s S3-compatible store. The MinIO alternatives post compares self-hosted S3 options; check that yours implements object lock and versioning before you rely on them. A target on the same storage cluster as production is not off-site.

Ransomware resistance: append-only, object lock and pull

A client that can delete its own backups will, sooner or later, delete them. Each tool solves this in a different layer.

Approach

restic

Borg 1.4

Kopia

Append-only server

rest-server --append-only; rclone serve restic --append-only

borg serve --append-only in authorized_keys, or append_only 1 in repo config

No separate append-only mode in the docs; use object lock, or a repository server so clients never hold storage keys

Object lock (WORM) on S3

Not a documented restic feature; any bucket-side lock sits outside restic

No (1.4)

--retention-mode COMPLIANCE --retention-period 30d, extension by full maintenance

Restrict server paths

rest-server --private-repos

--restrict-to-path, --restrict-to-repository

Per-user ACLs on repository server

Admin client for pruning

Separate trusted client runs forget/prune

Temporarily normal mode from a trusted client; review before compact

Maintenance owner runs full maintenance

Three cautions from the docs. restic warns that an attacker who adds junk snapshots to an append-only repository can make a careless forget --keep-last delete the real ones, so use --keep-within there. Borg’s append-only never deletes committed segments, but delete and prune still appear to work; you roll back with the transaction log, and plain rm on the server ignores append-only. Kopia warns that ransomware could abuse object lock by uploading large data with a long lock, so set bucket quotas. Borg 2 betas removed append-only and use a permissions setting (no-delete, write-only, read-only) through BORG_REPO_PERMISSIONS or borg serve --permissions.

A pull model, where the backup server reads clients with read-only access, is another answer; Borg documents pull backups over sshfs.

Retention, pruning and getting space back

Step

restic

Borg 1.4

Kopia

Choose what to keep

forget --keep-daily 7 --keep-weekly 4 ...

prune --keep-daily 7 --keep-weekly 4 ...

Policy: latest, hourly, daily, weekly, monthly, annual

Dry run

forget --dry-run

prune --dry-run --list

snapshot expire without --delete

Free space

prune (or forget --prune)

compact

Full maintenance, over one or more cycles

Default schedule

Whatever you schedule

Whatever you schedule

Quick about hourly, full every 24 h

In my drill, after deleting 80 MiB of files and keeping only the newest snapshot, restic released 83.4 MiB in one forget --prune and Borg 95.0 MiB after prune and compact. Kopia’s first full maintenance with --safety=none found 102.5 MB of unused contents but did not shrink the repository; the second cycle released 38.2 MiB and the third nothing more. That matches the docs, but size a Kopia bucket with headroom.

Check, verify and restore testing

Every tool has a cheap check and an expensive check. The cheap one confirms that the index and metadata are consistent. Only the expensive one reads the data and proves the bytes still decrypt and authenticate.

Level

restic

Borg 1.4

Kopia

Structure

check

check (also reads segment CRCs)

snapshot verify

All data

check --read-data

check --verify-data

content verify --download-percent=100 or snapshot verify --verify-files-percent=100

Partial data over time

--read-data-subset=1/5

--max-duration for repository part

--verify-files-percent=10

Real restore

restore latest --target

extract

snapshot restore

My tamper test (one flipped byte, details in the drill) showed the gap: restic check and a plain Kopia snapshot verify passed a damaged repository, while every full data check failed it. Borg’s plain check also failed it, because its repository part reads all segments. Schedule the expensive check, or a rolling subset, and do a real restore into a scratch directory at least monthly. Compare hashes, not just file counts.

Databases need consistent dumps first

File-level backup of a running PostgreSQL data directory gives you a copy that may not start. Take a consistent dump or a storage snapshot first, then back that up.

  • PostgreSQL: pg_dump for logical backups, or a base backup plus WAL archiving for point-in-time recovery. For clusters, the PostgreSQL high availability post covers Patroni and CloudNativePG, which bring their own backup integrations; a replica is not a backup.
  • restic can read a dump directly: restic backup --stdin-from-command -- pg_dump -Fc billing. If the command fails, restic does not record a snapshot from its output.
  • Borg 1.4 has borg create --content-from-command for the same purpose.
  • Kopia can snapshot stdin with --stdin-file, and policy actions can run a dump script before a snapshot.
  • Restore the dump into a test database in your monthly drill. A dump that pg_restore rejects gives false comfort.

Performance considerations

A few structural points hold regardless of anyone’s benchmark:

  • Borg 1.x runs one borg create on one core for chunking, compression and encryption. restic and Kopia use several cores, which matters most for first backups of large file servers.
  • Memory grows with repository size because each tool keeps or caches a chunk index. restic 0.19.0 reduced memory for check, copy, diff and stats; Borg’s FAQ covers scalability; Kopia’s content cache size is configurable.
  • Later backups are cheap when the tool skips unchanged files by size, mtime and inode; a no-change rerun took under a second for all three in my drill.
  • Larger average chunks (Borg, Kopia) cost more new data for small edits inside large files than restic’s 1 MiB average.
  • Compression settings change the picture more than the tool does: Kopia stored 355.2 MiB without compression and 223.7 MiB with a zstd policy, against restic’s 223.4 MiB.
  • The rest-server README says restic’s REST protocol is faster than SFTP, which moves data in small acknowledged packets.

Licences, history and governance

Item

restic

BorgBackup

Kopia

Licence at current tag

BSD 2-Clause (copyright Alexander Neumann, 2014)

BSD 3-Clause (The Borg Collective 2015 to 2026; Jonas Borgström 2010 to 2014)

Apache 2.0

Origins

Started 2014; 0.1.0 in September 2015

Fork of Attic in May 2015; 1.0 in March 2016

Repository from December 2015; first GitHub release May 2019

Governance

Community project on GitHub with a forum; release signing key of the founder

“The Borg Collective”; releases built and signed by maintainer Thomas Waldmann

Community project on GitHub; 2025 to 2026 release notes credit most changes to a small set of maintainers

Stable vs next

0.19.x only

1.4.x stable, 2.0 beta

0.23.x only

All three are permissively licensed, with none of the relicensing stories earlier Revisit.Tech posts had to cover. The real governance risk is the usual one for volunteer projects: a few people sign releases and review security fixes. That argues for pinning versions, verifying signatures and following advisories.

Security and CVEs

restic

In NVD keyword search and the repository’s GitHub security advisories on 13 October 2026, I found no CVE assigned to restic itself. The closest items are in a companion tool: rclone’s serve restic had CVE-2026-59733 (CVSS 8.8; --private-repos authorisation bypass with .. in the path, fixed in rclone 1.74.4, published 15 July 2026, 3:08 AM IST) and CVE-2026-71309 (CVSS 4.0 score 8.6; backend root escape with a leading ../, fixed in 1.75.0, published 6 August 2026, 1:43 AM IST). If you use rclone as the append-only endpoint for restic, run rclone 1.75.0 or later. restic 0.18.0’s chunker mitigation is a hardening change without a CVE.

BorgBackup

ID

Severity (source)

What

Fixed

GHSA-gfp8-w835-v44j (lists CVE-2026-62268)

Low (GitHub advisory)

A crafted archive could make borg extract follow a symlink, .. or hard link outside the target directory

1.4.5; 2.0.0b22; 1.2.x fix commits only

CVE-2023-36811

4.7 (CNA record)

Archive spoofing via a flaw in the authentication scheme

1.2.5 / 1.2.6 plus documented upgrade steps

CVE-2017-15914

(no CNA score)

Access control override in Borg servers 1.1.x before 1.1.3

1.1.3

CVE-2016-10099, CVE-2016-10100

(no CNA score)

Manifest spoofing and archive overwrite during recovery

1.0.9

The 2026 advisory needs repository write access and, for encrypted repositories, the key and passphrase, hence the low rating. On 13 October 2026 the CVE Program API returned “record does not exist” for CVE-2026-62268, so I cite the GitHub advisory, which also confirms no new 1.2 releases.

Kopia

ID

Severity

What

Fixed

CVE-2026-45695 (GHSA-2q4c-3mrw-63c3)

9.8 critical (GitHub CNA)

Server started with --insecure --without-password accepted unauthenticated requests; an SFTP storage config with external SSH arguments allowed -oProxyCommand command execution

0.23.0 (refuses insecure unauthenticated server on non-loopback addresses)

GHSA-j5vm-7qcc-2wwg

2.0 low

kopia repository status --json printed storage credentials

0.16.0

The CVE is serious but narrow: it needs a server started without a password and reachable over the network, exactly the shortcut people take on a “temporary” office server.

Practical controls

  1. Run restic 0.19.1, Borg 1.4.5 and Kopia 0.23.1 or newer, and rclone 1.75.0 or newer if it is in the path.
  2. Verify downloads with the published GPG keys or attestations before you install a backup binary on every server.
  3. Never start a Kopia server without a password or TLS, and do not expose it beyond the network that needs it.
  4. Give backup clients write-without-delete access (append-only server, object lock, --restrict-to-repository), and run pruning from a separate trusted host.
  5. Keep repository passwords and Borg key exports in a secrets manager and in one offline place.
  6. Do not extract untrusted archives with old Borg versions; treat archives from shared repositories as untrusted input.
  7. Alert on backup jobs that did not run, not only on jobs that failed.

Decision guide for the Surat scenario

The Surat firm needs: fourteen branch file servers, one PostgreSQL database, forty laptops, an existing S3-compatible bucket at head office, an off-site copy, and protection against a client that gets ransomware.

Option

Fit

Cost of the choice

Keep rsync + USB

Familiar

Copies damage forward; no versions; the March incident will repeat

restic to S3-compatible bucket

Good for branch servers and laptops; one binary; copy for off-site

Append-only needs rest-server or rclone in front; plan pruning from head office

Borg 1.4 over SSH to a backup VM

Good for Linux servers; mature; strong append-only story with borg serve

No native S3 in 1.4; single-threaded; Windows laptops are not its home ground

Kopia with repository server

Good for laptops (KopiaUI) and object lock on S3

Must set compression and watch maintenance; secure the server carefully after CVE-2026-45695

Recommendation for this invented Surat case:

  1. Make the repository not deletable by any branch server or laptop. That rules out the current design, whatever the tool.
  2. For the fourteen Linux branch servers, use restic to a rest-server in append-only mode at head office, or Borg 1.4 with borg serve --append-only --restrict-to-repository in authorized_keys. Both work; pick the one your team will read the docs for.
  3. For the forty laptops, use Kopia with a repository server and per-user accounts, so laptops never hold bucket keys. Set a compression policy on day one.
  4. Dump PostgreSQL with pg_dump -Fc to a file, back up that file, and restore it into a scratch database monthly.
  5. Run pruning and full checks only from one hardened admin host.
  6. Keep an off-site copy (restic copy or Kopia repository sync-to) in another city with different credentials.
  7. Keep passwords and key exports in the secrets manager, plus a sealed offline copy with the partner.
  8. Leave Borg 2 until it leaves beta.

Checklist before you trust a backup job

  1. Write down RPO, RTO and retention per data class (client files, database, laptops).
  2. Confirm which credential can delete backup data, and that no client holds it.
  3. Pin exact versions and verify signatures for every binary you roll out.
  4. Set compression explicitly (especially on Kopia) and record chunker and encryption choices.
  5. Store passwords and Borg keys in a secrets manager plus one offline copy.
  6. Use consistent database dumps or snapshots, never a live data directory.
  7. Schedule a full data check, or a rolling subset, at least monthly.
  8. Run a real restore to a scratch location monthly and compare hashes.
  9. Alert on missing runs, not just on errors.
  10. Test the full disaster path once a year: new machine, fresh install, only the documented password, restore.

Common mistakes

  1. Treating rsync or a cloud sync folder as backup.
  2. Letting every client hold credentials that can delete or overwrite the repository.
  3. Running only the cheap check and calling the repository verified.
  4. Losing the Borg key because repokey “keeps it in the repository” and the repository is the thing that died.
  5. Leaving Kopia compression off by accident and buying storage for it.
  6. Expecting Kopia to return space immediately after snapshot deletion.
  7. Running restic forget --keep-last against an append-only repository that an attacker may have filled with junk snapshots.
  8. Backing up a live PostgreSQL data directory and assuming it will start.
  9. Running Borg 2 betas in production because the features look finished.
  10. Starting kopia server with --insecure --without-password on a LAN “just for setup”.

A drill I ran on 13 October 2026

Environment: shared Linux VM (Debian 13, kernel 6.12), 8 vCPU, about 15.6 GiB RAM with about 6 GiB available, local overlay filesystem, no root, no Docker. Between about 10:19 and 10:28 AM IST I downloaded and verified the three tools and ran the scripted pass quoted here (10:26 to 10:27 AM IST). Load average rose from 1.01 to 2.80 because other work shares this VM.

What ran:

  • restic 0.19.1 official linux_amd64 binary; SHA256SUMS GPG signature good (fingerprint matches the restic docs) and SHA-256 matched.
  • BorgBackup 1.4.5 standalone borg-linux-glibc231-x86_64; GPG signature good against the fingerprint in Borg’s support docs. borg init -e repokey, default lz4 compression.
  • Kopia 0.23.1 linux-x64 tarball; checksums.txt.sig good against the Kopia Builder key and SHA-256 matched. Default settings, plus one variant repository with a global zstd compression policy for the first backup.
  • GNU time 1.10 (extracted from the Debian package) recorded wall time, CPU time and peak resident memory per command.

Dataset, all synthetic: 3,000 invoice-like text files, an 80 MiB SQL-like dump, ten 16 MiB random binaries and one 24 MiB random file stored in three places (402.7 MiB, 3,014 files). The change set appended to 30 text files, inserted 4 KiB into one binary, overwrote 64 KiB in another, added 10 MiB of new files, deleted 20 files, renamed a directory and grew the dump. Repositories were on the same local disk; numbers are from one run.

Repository size on disk (MiB)   restic   Borg    Kopia (no compression)
  after backup v1                223.4    249.3   355.2   (Kopia + zstd policy: 223.7)
  added by backup v2              17.8     24.1    28.3
  after keep-last-1 + reclaim    157.8    178.5   383.5 -> 345.3 after 2nd full maintenance

Wall time / peak RSS
  backup v1        restic 1.55 s / 323 MiB   Borg 2.90 s / 80 MiB   Kopia 0.77 s / 296 MiB
  no-change rerun  restic 0.79 s / 61 MiB    Borg 0.82 s / 81 MiB   Kopia 0.18 s / 119 MiB
  backup v2        restic 1.01 s / 199 MiB   Borg 1.11 s / 81 MiB   Kopia 0.42 s / 155 MiB
  full data check  restic 1.17 s / 95 MiB    Borg 1.55 s / 80 MiB   Kopia 1.02 s / 238 MiB
  full restore     restic 1.34 s / 144 MiB   Borg 1.69 s / 83 MiB   Kopia 0.47 s / 376 MiB
  init             restic 3.29 s (scrypt)    Borg 0.62 s            Kopia 0.49 s
  peak CPU use     restic 285 %              Borg <= 100 %          Kopia 386 % (zstd variant)

Restore vs source: 2,996 / 2,996 files, 0 hash, mtime or mode mismatches, diff -r clean (all three)
Wrong password: refused by all three (exit codes 12, 2, 1)
Tamper (one byte flipped inside live data, copy of each repo):
  restic  check: pass (missed)        check --read-data: FAIL, named the pack
  Borg    check: FAIL                 check --verify-data: FAIL
  Kopia   snapshot verify: pass (missed)  content verify 100 %: FAIL  verify-files 100 %: FAIL  restore: FAIL

What this shows:

  • All three deduplicated the triple-stored file and restored identical content, timestamps and permissions.
  • Defaults decide sizes: Kopia without a compression policy stored about 60 % more than restic; with zstd it matched.
  • Borg stayed on one core at about 80 MiB; restic and Kopia used several cores and more memory.
  • Space came back at once for restic and for Borg after compact, and only partly, over cycles, for Kopia.
  • My first Kopia tamper attempt hit dead bytes left in a pack after retention, so Kopia correctly reported nothing; the quoted result is a repeat with a byte inside live content.

Limits of the drill: one VM, one run, data in page cache, local repositories only (no SFTP, S3, rest-server or borg serve), no append-only or object lock test, no Windows or macOS, small repository sizes where index memory does not matter, and timings that include process start-up. This is a smoke test, not a benchmark. Artefacts (README, scripts, logs, results) are under /workspace/revisit/drill33/. No servers were started; binaries, repositories and the dataset were deleted afterwards.

Unlearn / re-learn

Unlearn

  • A nightly sync to a NAS is a backup.
  • “Encrypted” means safe from ransomware.
  • check passing means the data is readable.
  • Deleting snapshots frees space straight away.
  • A replica database or a copied data directory replaces a dump.
  • A beta that has been around for years is production-ready.

Re-learn

  • Ask who can delete backup data before you ask which tool to use.
  • Separate the cheap structural check from the expensive data check, and schedule both.
  • Set compression, retention and maintenance explicitly; defaults differ by tool.
  • Keep passwords and keys in a secrets manager plus one offline copy.
  • Practise a full restore, including the database, before you need it.

Closing

Self-hosted backups in 2026 come down to three solid, permissively licensed tools with different centres of gravity. Learn their repository models: restic’s packs and many backends, Borg’s segments and borg serve, Kopia’s policies, maintenance and repository server. Unlearn the habit of treating sync, snapshots or replicas as backups, and of trusting a green check. Re-learn the current versions and lines: restic 0.19.1, Borg 1.4.5 stable with Borg 2 still in beta, Kopia 0.23.1 with compression off until you turn it on. Practise with a small drill like the one above: one dataset, one change set, one full check, one restore, one flipped byte. Apply one design where no client can delete its own backups, the passwords live somewhere you can reach on a bad day, and the monthly restore test is on someone’s calendar.

Sources

restic

BorgBackup

Kopia

Security (CVE Program records and GitHub advisories)

comments powered by Disqus

Releted Posts

Distributed tracing in 2026: revisit Jaeger, Grafana Tempo and SigNoz before you store another span

Picture a bus, train and hotel booking platform in Kochi (an invented example, not a real client). Customers book from an Android app, an iOS app and a web app.

Read more

Feature flags in 2026: revisit Unleash, Flagsmith and GrowthBook before you hard-code another release toggle

Picture a test-preparation and online classes platform in Jaipur (an invented example, not a real client). Students use an Android app, an iOS app and a React web app.

Read more

Lakehouse table formats in 2026: revisit Apache Iceberg, Delta Lake and Apache Hudi before you pick another format

Picture a payments and lending analytics platform in Hyderabad (an invented example, not a real client). Card authorisations and EMI schedules still land in PostgreSQL 16.

Read more