Files
shadow/SECURITY.md
T
Pierre Warnier 52c2debe8b release: publish a labelled static musl archive (#224) (#237)
* shadow-core: link libcrypt only where it exists; refuse pam on static musl

musl implements crypt(3) inside libc and ships no libcrypt. Asking for
-lcrypt there made a cross-build for x86_64-unknown-linux-musl fall through
to the host's glibc-built libxcrypt and fail on glibc-only symbols; Alpine
only worked because musl-dev ships an empty libcrypt.a.

Linux-PAM loads its modules with dlopen, which static musl does not have,
and no distribution ships libpam.a. Building the pam feature into a
crt-static musl binary is therefore a configuration error; reject it at
compile time instead of producing a binary whose authentication path can
never work.

The crypt tests stated the musl behaviour wrongly (musl does honour
rounds=; it lacks yescrypt). They now assert the real behaviour per target
instead of skipping.

* release: publish a static musl archive next to the glibc one

dist cannot vary cargo features per target and pam must be off for musl,
so the musl archive is built by 'make dist-musl' and attached by dist as an
extra artifact of the same release. The target enforces the lockfile,
checks the binary has no DT_NEEDED entry and packs it with the licence,
changelog, README and PLATFORM-SUPPORT.md so the trade-off travels with
the binary. The archive name carries a -static suffix so it is never
mistaken for the glibc build.

CI runs the same make target on every pull request, smoke-tests the
archive, runs shadow-core's unit tests against static musl and checks that
the pam feature is rejected there, so a tag is never the first time the
archive is built.

* docs: describe both release archives and what the static musl one gives up

The README now lists the two archives side by side with the one question a
reader has to answer (is PAM, NSS or yescrypt needed on this host?), and
PLATFORM-SUPPORT.md is rewritten around the archive that now exists: how
it is built, which CI job guards it, and the exact effect of each gap.
CONTRIBUTING listed two unsafe-permitted modules; there are three.

* chore: use the canonical uutils/shadow repository URL

The repository is uutils/shadow; the old shadow-rs name is a redirect. The
README badges already used the new name while package metadata, the --help
footer and SECURITY.md still pointed at the old one.
2026-09-04 10:04:38 +02:00

1.9 KiB

Security Policy

Scope

shadow-rs reimplements setuid-root tools that write to /etc/passwd, /etc/shadow, and /etc/group. Security vulnerabilities in this code can lead to privilege escalation, account takeover, or system lockout.

We take security issues extremely seriously.

Reporting a Vulnerability

Do NOT open a public GitHub issue for security vulnerabilities.

Instead, please report vulnerabilities via GitHub's private vulnerability reporting feature:

  1. Go to https://github.com/uutils/shadow/security/advisories
  2. Click "New draft security advisory"
  3. Fill in the details

If private advisory reporting is unavailable, contact the maintainers directly using a private channel (for example, the email address listed in a maintainer's GitHub profile). Do not open a public GitHub issue for security vulnerabilities.

What to Include

  • Description of the vulnerability
  • Steps to reproduce
  • Affected versions / commits
  • Impact assessment (privilege escalation, data leak, DoS, etc.)
  • Suggested fix (if you have one)

Response Timeline

  • Acknowledgment: within 48 hours
  • Initial assessment: within 7 days
  • Fix and disclosure: coordinated, typically within 30 days

Supported Versions

Only the latest version on the main branch is supported during pre-1.0 development.

Security Design Principles

  • Memory safety: Rust eliminates buffer overflows, use-after-free, and uninitialized memory reads
  • Password zeroing: sensitive data is zeroed in memory via the zeroize crate before deallocation
  • Atomic file operations: lock → write tmp → fsync → rename prevents partial writes and corruption
  • Stale lock detection: PID-based detection prevents permanent lockout from crashed processes
  • PAM delegation: password changes go through PAM — we do not implement our own password hashing
  • No GPL code: clean-room implementation prevents license contamination