From 52c1db7ef05e9b008d80f8a1c77314ef1b147597 Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 13 Oct 2026 04:53:33 +0300 Subject: [PATCH] fix: restrict access to unsanitized intermediate rootfs archives --- hydra/build.py | 4 ++++ tests/test_image.py | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/hydra/build.py b/hydra/build.py index 5c98c58..62af262 100644 --- a/hydra/build.py +++ b/hydra/build.py @@ -413,6 +413,10 @@ fi''' source_inputs = image.source_identity(self.source_dir) self.record('rootfs', complete=False) original = self.work / 'artifacts/builder-rootfs.tar' + if original.is_symlink() or not original.parent.resolve().is_relative_to(self.work): + raise BuildError('Raw export output must remain inside the dedicated work directory') + original.touch(mode=0o600, exist_ok=True) + original.chmod(0o600) # The unsanitized intermediate can contain builder-private trust. self.pod('export', '--output', str(original), self.name) snapshot = image.digest(original) assembler = self.assembly(snapshot) diff --git a/tests/test_image.py b/tests/test_image.py index de09ecd..55c0487 100644 --- a/tests/test_image.py +++ b/tests/test_image.py @@ -283,7 +283,10 @@ class ImageBuildTests(unittest.TestCase): self.builder.run = lambda *args, **kwargs: subprocess.CompletedProcess(args, 0, 'commit\n', '') def pod(*args, **kwargs): if args[0] == 'export': - (artifacts / 'builder-rootfs.tar').write_bytes(b'exported fixture') + snapshot = artifacts / 'builder-rootfs.tar' + self.assertTrue(snapshot.is_file(), 'raw snapshot must be created privately before export') + self.assertEqual(snapshot.stat().st_mode & 0o777, 0o600) + snapshot.write_bytes(b'exported fixture') elif args[0] == 'exec' and 'configure-rootfs.sh' in args[-1]: for name in ('vmlinuz', 'initramfs-live.img', 'squashfs.img'): (artifacts / name).write_bytes(b'artifact')