Skip to content

Release 1.4.5#9912

Merged
ThomasWaldmann merged 10 commits into
borgbackup:1.4-maintfrom
ThomasWaldmann:rel145
Jul 19, 2026
Merged

Release 1.4.5#9912
ThomasWaldmann merged 10 commits into
borgbackup:1.4-maintfrom
ThomasWaldmann:rel145

Conversation

@ThomasWaldmann

Copy link
Copy Markdown
Member

No description provided.

@ThomasWaldmann
ThomasWaldmann marked this pull request as draft July 18, 2026 19:40
@codecov

codecov Bot commented Jul 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.87179% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.62%. Comparing base (e4e2229) to head (1b7d327).
⚠️ Report is 5 commits behind head on 1.4-maint.

Files with missing lines Patch % Lines
src/borg/archive.py 93.75% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##           1.4-maint    #9912      +/-   ##
=============================================
+ Coverage      82.03%   82.62%   +0.59%     
=============================================
  Files             38       38              
  Lines          11396    11432      +36     
  Branches        1797     1803       +6     
=============================================
+ Hits            9349     9446      +97     
+ Misses          1462     1408      -54     
+ Partials         585      578       -7     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

ThomasWaldmann and others added 9 commits July 18, 2026 23:20
looks like they removed the pip and virtualenv package.
the man page formatter can not deal with row or col spans.
…mbedded "..")

CVE-2026-62268 Fix 1/2

A maliciously crafted archive could contain a symlink (e.g. "evil" -> "/etc")
followed by an item below it ("evil/passwd"), or an item whose path embeds ".."
(e.g. "a/../../etc/passwd"). When extracting such items, borg followed the symlink
/ resolved the ".." in both the "remove existing file" step and the open()/mkdir()/
symlink() step, so it could delete or overwrite files outside the extraction
directory.

Note: sounds bad, but no big issue in practice: to create such a malicious archive,
the attacker would need repository access and (for encrypted or authenticated repos)
also the borg key and passphrase.

borg create never produces such archives (it does not follow symlinks and stores
normalized relative paths), so extract_item() now verifies, before any destructive
operation, that the item's parent path contains no ".." and no symlinked (or other
non-directory) component. Unsafe items are skipped with a warning (EXIT_WARNING)
and extraction continues. Verified-safe parent directories are cached per extraction
(Archive.safe_dirs) so each directory is lstat'd at most once.

Added regression tests for both attack vectors and a benign deep-tree extraction.

Also: skip redundant make_parent stat using safe_dirs cache

Performance optimization building on the parent-path security fix: the parent
path guard in extract_item already lstat's every existing parent directory and
records it in Archive.safe_dirs. make_parent therefore no longer needs to call
os.path.exists() for a parent that is already known to be a real directory - it
returns early on a safe_dirs hit, and caches directories it has to create (and
dest) so later items skip the stat too.

This roughly halves the per-item directory-metadata syscalls in the common case
(deep tree, shared parents) without changing behavior.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CVE-2026-62268 Fix 2/2

The hardlink source (item.source) was used unvalidated as the os.link() target
during extraction. A maliciously crafted archive could set a source that traverses
a symlink (e.g. "evil/secret" with "evil" -> "/etc") or contains "..", causing
borg to hardlink an arbitrary external file (e.g. /etc/shadow) into the extracted
tree - an information disclosure, especially dangerous when restoring as root.

Note: sounds bad, but no big issue in practice: to create such a malicious archive,
the attacker would need repository access and (for encrypted or authenticated repos)
also the borg key and passphrase.

extract_helper now validates the hardlink source path with the same
Archive._check_safe_parent() check used for item paths, refusing unsafe ones with a
warning (and continuing with the rest of the archive). os.link() is now called with
follow_symlinks=False (where supported) so a symlinked final source component links
the symlink itself - a faithful restore - rather than the external file it targets.

Adds BackupHardlinkSourceError and regression tests for both the symlinked-source and
embedded-".." source vectors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ThomasWaldmann
ThomasWaldmann marked this pull request as ready for review July 18, 2026 22:08
@ThomasWaldmann

Copy link
Copy Markdown
Member Author

Haiku test failure: haiku specific, does not fail on other OSes. #9913
NetBSD: python sometimes segfaults on NetBSD, super annoying.

@ThomasWaldmann
ThomasWaldmann merged commit d176d42 into borgbackup:1.4-maint Jul 19, 2026
26 of 29 checks passed
@ThomasWaldmann
ThomasWaldmann deleted the rel145 branch July 19, 2026 05:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant