Skip to content

Major Security Improvements, Fixed Plugin Installs, + More#13

Merged
freepicheep merged 10 commits intomainfrom
security
Mar 3, 2026
Merged

Major Security Improvements, Fixed Plugin Installs, + More#13
freepicheep merged 10 commits intomainfrom
security

Conversation

@freepicheep
Copy link
Copy Markdown
Owner

Highlights

  • Added fail-closed checksum verification for downloaded Nushell/plugin release assets.
  • Hardened install security by rejecting insecure http:// git sources.
  • Reworked archive extraction to avoid shell-based extraction and block unsafe archive entries.
  • Improved plugin install reliability (semver tag selection, .tar.xz support, stale lockfile detection fixes).

Added

  • qv install --allow-unsigned (explicit insecure override).
  • qv install --no-build-fallback (disable plugin source-build fallback).
  • [security] require_signed_assets = true config support (default enabled).
  • Lockfile metadata for plugin release assets:
    • asset_sha256
    • asset_url

Changed

  • --frozen now enforces strict security behavior:
    • signed assets required
    • unsigned override disabled
    • build fallback disabled
  • Git cache directory naming now uses SHA-256 of the URL (collision-resistant).
  • Cached repo origin is validated to prevent mismatch/reuse of wrong repository.
  • Core Nushell plugins with a Nu version are installed directly into the shared plugin installs directory.

Security Hardening

  • Reject insecure dependency sources using http:// (manifest and CLI normalization paths).
  • Added dependency/plugin/binary name validation to reduce path traversal and unsafe names.
  • Checksum source detection supports:
    • SHA256SUMS, SHA256SUMS.txt, checksums.txt
    • <asset>.sha256
  • Checksum parsing supports common formats (POSIX, BSD, single-hash lines).
  • Archive extraction protections added (including path traversal/symlink safety checks).

Fixed

  • Plugin installer now handles .tar.xz release assets.
  • “Latest tag” lookup is now semver-aware (fixes lexicographic tag ordering bugs).
  • Stale lockfile detection improved for dependency/plugin changes (including plugin bin changes).
  • Plugin linking behavior improved for idempotence and target consistency.

Documentation

  • README now documents supply-chain security model and CI recommendation:
    • qv install --frozen --no-build-fallback

1. Path/name safety enforcement (blocks traversal)
      - Added shared validators and relative-path normalizer in
safety.rs.
      - Enforced dependency/plugin/bin name validation in:
      - manifest.rs
      - resolver.rs
      - installer.rs
      - main.rs
      - remove / remove --global now reject unsafe names before
filesystem operations.

  2. Removed user-controlled temp/staging path components
      - Replaced temp/staging directory naming that included dependency
names with unique random-ish IDs in:
      - resolver.rs
      - installer.rs

  3. Git cache hardening
      - Replaced lossy URL→dirname mapping with SHA-256 URL keying in
git.rs.
      - Added origin URL verification for cached repos before fetch;
mismatches now fail hard.

  4. Frozen mode integrity enforcement
      - --frozen now verifies installed artifact checksums against
lockfile and fails on mismatch/missing checksum.
      - --frozen no longer rewrites lockfiles.
      - Applied to local and global install flows in installer.rs.

  5. Export error handling
      - Git tree export no longer ignores write/create failures; IO/git
errors now abort and propagate in git.rs.

  6. Security regression tests added
      - New tests in:
          - safety.rs
          - git.rs
          - installer.rs

  Validation

  - Ran cargo fmt
  - Ran cargo test: 95 passed, 0 failed

  Remaining gap

  - I did not add cryptographic signature/checksum verification of
remote release assets (Nushell/plugin downloads) yet; current trust
model is still HTTPS + source host trust.
What changed

  1. Added strict asset integrity verification in installer flow for:

  - Nushell GitHub release archives
  - Plugin GitHub release assets
    Files: installer.rs

  2. Added checksum helpers in installer:

  - download_release_checksums(...)
  - parse_expected_sha256(...)
  - sha256_file(...)
  - verify_downloaded_asset(...)

  3. Enforced fail-closed behavior by default:

  - Missing checksum source, parse failure, or digest mismatch now
errors with distinct types and actionable messages.
  - New error variants added in error.rs.

  4. Added policy knobs:

  - CLI flags on install: --allow-unsigned, --no-build-fallback
    File: cli.rs
  - Config setting: [security] require_signed_assets = true|false
(default true)
    File: config.rs
  - --frozen now forces secure behavior (signed assets required;
unsigned override disabled; build fallback disabled).

  5. Plugin fallback behavior updated:

  - Verification failures do not continue unless unsigned mode is
explicitly active.
  - High-visibility security warnings are emitted before local cargo
source-build fallback.

  6. Lockfile metadata extended:

  - Optional asset_sha256
  - Optional asset_url
    File: lockfile.rs
  - In frozen installs, if asset_sha256 is present, plugin re-downloads
must match it.

  7. Wiring updates for CLI → main → installer:

  - Added new install arguments propagation.
    File: main.rs

  8. Documentation updates:

  - Added Supply Chain Security guidance and CI recommendation (qv
install --frozen --no-build-fallback).
    File: README.md
previously it was building the plugin with cargo automatically if no
release assets were found. not good. it now presents a y/n option.

lockfile was stale if you updated the specs for a dep. it now checks if
any of the features of a dep have changed.
I replaced the vulnerable shell-based archive extraction with safe
in-process extraction that blocks dangerous archive entries.

  What changed

  1. Replaced tar/unzip command extraction with Rust-based extractors in
installer.rs:1429.
  2. Added strict checks during extraction:
  3. Reject .., absolute, and otherwise unsafe paths via normalized path
validation.
  4. Reject symlink/hardlink entries in tar and symlink entries in zip.
  5. Allow only normal files/directories for extraction.
  6. Added regression tests to ensure malicious archives are rejected:
  7. Tar symlink payload rejection.
  8. Zip traversal (../...) rejection.
     Tests are in installer.rs:3341.
  9. Added archive libraries in Cargo.toml:24:
  10. flate2
  11. tar
  12. xz2
  13. zip
@freepicheep freepicheep merged commit 66f3efe into main Mar 3, 2026
6 checks passed
@freepicheep freepicheep deleted the security branch March 3, 2026 16:57
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