Skip to content

fix: security audit findings, bug fixes, and CI hardening#37

Merged
timhartmann7 merged 11 commits into
timhartmann7:mainfrom
PowerAppsDarren:fix/security-audit-findings
Jun 6, 2026
Merged

fix: security audit findings, bug fixes, and CI hardening#37
timhartmann7 merged 11 commits into
timhartmann7:mainfrom
PowerAppsDarren:fix/security-audit-findings

Conversation

@PowerAppsDarren
Copy link
Copy Markdown
Contributor

Summary

Community security audit and code review covering shell injection, config file permissions, SFTP path validation, CI supply chain, and several functional bugs.

Security fixes:

  • Validate public key format before embedding in shell commands (prevents injection via crafted key comments)
  • Add input validation to force_sshd_directive() to prevent sed injection
  • Narrow Include directive commenting to cloud-init only (avoids disabling legitimate sshd security policies)
  • Set 0600 permissions on config files that may contain credentials
  • Thread host_name through SFTP task loop (was sending empty string in disconnect events)
  • Add null byte and path traversal guards to SFTP upload/download

Bug fixes:

  • Fix collect_output to continue reading after Eof so ExitStatus is not lost
  • Set pending_ops for multi-file remote delete (progress popup was closing after first file)
  • Collect all local delete errors instead of only the last one
  • Replace blocking std::fs::remove_dir with tokio::fs::remove_dir in async context
  • Make terminal restore unconditional (all steps run even if disable_raw_mode fails)
  • Remove dead pending_connect/connect_system_ssh code path
  • Batch docker inspect with xargs -n 50 to avoid ARG_MAX with many containers

CI/supply chain:

  • Pin all GitHub Actions to immutable commit SHAs
  • Add SHA256SUMS verification to install.sh
  • Fetch man page from tagged release commit instead of mutable main branch

Crypto hardening:

  • Remove id_dsa from default key paths (DSA is broken, removed from OpenSSH 9.8)
  • Add TOFU warning log when accepting unknown host keys

Not included in this PR (discussed in issues, need maintainer input):

Test plan

  • cargo test — all 26 tests pass
  • cargo clippy -- -D warnings — zero warnings
  • cargo fmt --check — clean

Related issues

Refs #32, #33, #34, #35, #36

PowerAppsDarren and others added 11 commits June 4, 2026 10:20
- Validate public key content after reading from disk: reject keys
  containing newlines, carriage returns, or null bytes, and verify the
  key type prefix matches ssh-ed25519/ssh-rsa/ecdsa-sha2-*.
- Add input validation to force_sshd_directive() to prevent sed
  injection if ever called with user-supplied arguments.
- Narrow Include directive commenting to only target cloud-init
  (/etc/ssh/sshd_config.d/) instead of all Include directives.
- Replace ls-based rollback with find for safer filename handling.

Addresses shell injection risks in remote command construction.

Refs: timhartmann7#32

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…iles

- Set restrictive file permissions (0600) on hosts.toml, snippets.toml,
  and config.toml after writing, since they may contain credentials.
- Clean up .tmp files if the atomic rename step fails, preventing stale
  temp file accumulation in the config directory.

Refs: timhartmann7#35

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Split Eof from Close/None in collect_output match arms so ExitStatus
  messages arriving after Eof are correctly captured.
- Remove id_dsa from default key paths (DSA is cryptographically broken,
  removed from OpenSSH 9.8).
- Add TOFU warning log when accepting an unknown host key.

Refs: timhartmann7#34
Refs: timhartmann7#35

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…al restore

- Set pending_ops before sending remote delete commands so the progress
  indicator counts down correctly instead of closing after the first file.
- Collect all local delete errors instead of only reporting the last one.
- Replace blocking std::fs::remove_dir with tokio::fs::remove_dir to
  avoid blocking the async worker thread.
- Make terminal restore unconditional: run all restore steps even if
  disable_raw_mode fails, preventing a broken shell on error.
- Remove dead pending_connect/connect_system_ssh code path (never set).

Refs: timhartmann7#34

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ation

- Thread host_name into sftp_task_loop so SftpDisconnected events carry
  the actual host name instead of an empty string.
- Add null byte checks to do_download and do_upload.
- Add path traversal (.. component) guard to do_upload, matching the
  existing protection in do_download.

Refs: timhartmann7#34
Refs: timhartmann7#36

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ners

Use xargs -n 50 to batch container IDs instead of expanding all IDs
in a single command substitution, which fails silently when the
argument list exceeds ARG_MAX (~2 MiB) with hundreds of containers.

Refs: timhartmann7#36

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Pin all GitHub Actions to immutable commit SHAs instead of mutable
  tags (v4, v2, stable) to prevent supply chain attacks via tag
  force-push.
- Add SHA256SUMS verification to install.sh after downloading the
  release archive, before extraction and installation.
- Fetch man page from the tagged release commit instead of the mutable
  main branch.

Refs: timhartmann7#33

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@timhartmann7 timhartmann7 merged commit 9361f26 into timhartmann7:main Jun 6, 2026
3 checks passed
@timhartmann7
Copy link
Copy Markdown
Owner

Hey @PowerAppsDarren - really happy to see this, thank you for digging into the project!

I pushed a few small follow-ups on top of your commits:

  • macOS shasum fallback in the installer - it only had sha256sum, which isn't available on macOS by default.
  • Portable backup lookup in the sshd rollback.
  • Corrected two pinned action SHAs - dtolnay/rust-toolchain and softprops/action-gh-release pointed at commits that don't actually exist upstream, so CI would've failed to resolve them.

@PowerAppsDarren
Copy link
Copy Markdown
Contributor Author

Thanks, man! You're a genius with this project!

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.

2 participants