Skip to content

Security: Unmanaged-Bytes/bit-crafts

Security

SECURITY.md

Security policy

Heads-up before reading further

Please skim the About this project section of the README first. bit-crafts is a personal, AI-pair- programmed R&D codebase maintained by a single person. Treat the guidance below as best-effort, not a contract — there is no on-call rotation, no SLA, and no security team behind this project.

Supported versions

Only the main branch is supported; tagged releases are point-in-time snapshots, not LTS branches. Security fixes land on main and ship in the next tag.

Reporting a vulnerability

Do not open a public GitHub issue for security bugs.

Use GitHub's private vulnerability reporting on this repository (Security tab → Report a vulnerability). Include:

  • A description of the issue (what / where / impact).
  • A minimal reproduction (command line, input file, dataset, expected vs. observed behaviour).
  • The version (bchash --version, git commit, distribution).

I read security advisories when time allows; I cannot promise a reply, a triage, or a fix. If a report sits unanswered for 90 days, please consider yourself free to publish.

Scope

In scope:

  • Memory safety bugs in any bc-* library or bc-* tool (UAF, OOB, heap corruption, double-free, use-of-uninitialized).
  • Path traversal or symlink attacks in the walker / manifest / duplicate-prune paths.
  • Subprocess argv injection from the Vigil GTK4 frontend (applications/vigil/) into the bchash CLI it spawns.
  • Sandbox-escape or XDG-state misuse in the Vigil Snap (strict confinement) or Flatpak (--filesystem=home:ro) packagings.
  • Hash collisions exploitable in the verify / diff paths (cross-tool digest mismatch, length-extension, ...).
  • Privilege escalation via bcintegrity verify / bcduplicate prune acting on attacker-controlled trees.

Out of scope:

  • Performance regressions (file an issue).
  • DoS via legitimate workloads (very large trees, very deep nesting).
  • Findings that require root access on the runner host.
  • Issues in third-party dependencies (liburing, libxxhash, libssl, libblake3) — report those upstream.

Known surface

The walker descends into pseudo-filesystems (/proc, /sys, /dev, /run, /tmp) only when explicitly named as the root. Otherwise these mounts are filtered. See subprojects/bc-io/src/path/bc_io_path.c for the implementation.

bcintegrity and bchash open files with O_NOFOLLOW by default; --follow-symlinks opts in to following links and runs cycle detection.

CLI parsers (bc_runtime_cli_parse, the per-tool dispatchers, the manifest reader, the glob filter) are continuously fuzzed under -Dfuzzing=true (see tools/*/fuzzing/, subprojects/bc-runtime/fuzzing/).

Vigil (desktop frontend) surface

Vigil never links against the C libraries. It spawns bchash via Gio.SubprocessLauncher.spawnv(argv) — list-form argv, no shell, no string concatenation; the -- argv separator is always emitted before positional path arguments. There is no subprocess.run, no shell=True, no os.system anywhere under applications/vigil/src/.

Persistent state lives in $XDG_DATA_HOME/bitcrafts-vigil/ (default ~/.local/share/bitcrafts-vigil/) — directory mode 0o700, SQLite file mode 0o600 (and on the -wal / -shm sidecars). In Snap the prefix is ~/snap/bitcrafts-vigil/current/.local/share/bitcrafts-vigil/, in Flatpak it's ~/.var/app/com.unmanagedbytes.BitCraftsVigil/data/bitcrafts-vigil/. Both are isolated from other applications by their respective sandbox.

Snap plug list: home, desktop, desktop-legacy, wayland, x11, opengl — no network, no removable-media, no system-observe. Flatpak finish-args: --filesystem=home:ro (read-only home), --filesystem=xdg-download:create (export-bundle write target), --socket=wayland, --socket=fallback-x11, --device=dri. No network access in either packaging.

openat2 confinement

bchash check / diff

bchash check (and bchash diff, reserved) accept a --root=DIR option. When set, the root directory is opened as a dirfd and relative entry paths from the manifest are resolved under that directory.

On Linux 5.6+ the underlying openat2(2) syscall enforces RESOLVE_BENEATH | RESOLVE_NO_SYMLINKS to prevent path traversal and symlink escapes. When the kernel does not support openat2 (ENOSYS), a single warn-once message is emitted to stderr and verification falls back to the plain open() path:

bchash: kernel lacks openat2; running without RESOLVE_BENEATH confinement

Default root when --root is not provided: dirname(manifest-path). Manifests that contain absolute paths are rejected outright with BC_RUNTIME_EXIT_DATAERR (65) — re-generate with bchash hash to obtain a relative-path manifest.

bcintegrity verify — fail-closed (BREAKING, 2026-05-13)

bcintegrity verify <root> <manifest> now requires Linux 5.6+ and uses the same openat2(RESOLVE_BENEATH | RESOLVE_NO_SYMLINKS) confinement at the kernel level. Unlike bchash's graceful fallback, bcintegrity fails closed on legacy kernels:

bcintegrity: kernel lacks openat2 (Linux >= 5.6 required); refusing to verify without confinement

Exit code is BC_RUNTIME_EXIT_NOPERM (77). There is no --allow-legacy-kernel opt-out: <root> is always explicit, so the attack surface is always intentional, so the confinement is always required. Re-mount the workload onto a 5.6+ host if you need verify on an older kernel.

There aren't any published security advisories