Back to Blog
high SEVERITY7 min read

How unsafe package download verification happens in shell scripts and how to fix it

A critical vulnerability in the DragonFly installation script allowed attackers to inject malicious packages by downloading and installing software without verifying integrity checksums. The fix adds SHA256 verification before installation, ensuring only legitimate packages are executed with elevated privileges.

O
By Orbis AppSec
Published June 29, 2026Reviewed June 29, 2026

Answer Summary

This is an insecure software supply chain vulnerability (CWE-494) in shell installation scripts where downloaded packages lack integrity verification. An attacker compromising the download server could inject malicious code that runs with sudo privileges. The fix adds mandatory SHA256 checksum validation before package installation, preventing tampering and ensuring authenticity.

Vulnerability at a Glance

cweCWE-494 (Download of Code Without Integrity Check)
fixAdd SHA256 checksum verification before extraction and installation
riskRemote Code Execution with elevated privileges (sudo)
languageShell/Bash
root causeDownloaded packages installed without checksum or signature validation
vulnerabilityInsecure Package Download without Integrity Verification

How Unsafe Package Download Verification Happens in Shell Scripts and How to Fix It

In the l1vm project's install/install-DragonFly.sh script, we discovered a high-severity supply chain vulnerability that could allow attackers to inject malicious code into systems during the installation process. The script downloaded a base package from an external server and immediately extracted and installed it—without verifying that the package hadn't been tampered with or replaced by an attacker.

This is a critical flaw in software supply chain security. Let's examine how it happened, why it's dangerous, and how the fix prevents future exploitation.

Introduction: When Installation Scripts Become Attack Vectors

The install/install-DragonFly.sh file is responsible for bootstrapping a development environment. Like many installation scripts, it downloads a pre-built package (l1vm-base-pkg.tar.bz2) from https://midnight-coding.de/blog/assets/l1vm/ and installs it system-wide.

Here's the problem: the script trusts that whatever is downloaded is legitimate, without any verification.

This creates a dangerous scenario:
- If the server hosting the package is compromised, attackers can replace the legitimate package with malicious code
- If an attacker performs a DNS hijack or BGP hijack, they can redirect downloads to their own server
- Even with HTTPS, a compromised server certificate or certificate authority can serve malicious content
- The script runs with sudo privileges, meaning any injected code executes as root

The vulnerability chain is short but devastating: compromised download server → malicious package downloaded → executed with root privileges → complete system compromise.

The Vulnerability Explained: Missing Checksum Verification

Let's examine the original vulnerable code:

echo "Install base package with includes and programs..."
../scripts/download-pkg.sh https://midnight-coding.de/blog/assets/l1vm/l1vm-base-pkg.tar.bz2 l1vm-base-pkg.tar.bz2

cd ..

The problem: After downloading l1vm-base-pkg.tar.bz2, the script immediately proceeds to extract and install it. There is no verification that:
- The file hasn't been modified in transit (though HTTPS helps here)
- The file hasn't been replaced on the server
- The file matches what the developers intended to distribute
- The file is actually a valid tar.bz2 archive and not malicious content

Attack Scenario: Server Compromise

Imagine an attacker compromises midnight-coding.de:

  1. The attacker replaces l1vm-base-pkg.tar.bz2 with a malicious archive containing a backdoor
  2. A developer runs the installation script: bash install/install-DragonFly.sh
  3. The script downloads the malicious package over HTTPS (which protects transport, not content)
  4. The script extracts and installs the malicious package with sudo privileges
  5. The backdoor is now running on the developer's system with root access

The developer has no way to detect the compromise because the script provides no integrity check.

Why HTTPS Isn't Enough

Developers often assume HTTPS provides complete security. It doesn't. HTTPS protects against:
- Network eavesdropping
- Man-in-the-middle attacks on the network path

HTTPS does not protect against:
- Compromised servers (the source of the content)
- Compromised or malicious certificates
- DNS hijacking to a malicious server with a valid certificate for that domain
- Insider threats at the hosting provider

Cryptographic verification of the package itself is essential.

The Fix: Implementing SHA256 Checksum Verification

The fix adds mandatory checksum verification before installation:

echo "Install base package with includes and programs..."
# Known-good SHA256 checksum for l1vm-base-pkg.tar.bz2 - update when the package is updated
EXPECTED_SHA256="PLACEHOLDER_REPLACE_WITH_KNOWN_SHA256_HASH"
../scripts/download-pkg.sh https://midnight-coding.de/blog/assets/l1vm/l1vm-base-pkg.tar.bz2 l1vm-base-pkg.tar.bz2

ACTUAL_SHA256=$(sha256 -q l1vm-base-pkg.tar.bz2 2>/dev/null || openssl dgst -sha256 l1vm-base-pkg.tar.bz2 2>/dev/null | awk '{print $NF}')
if [ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]; then
    echo "ERROR: Checksum verification FAILED for l1vm-base-pkg.tar.bz2!"
    echo "Expected: $EXPECTED_SHA256"
    echo "Actual:   $ACTUAL_SHA256"
    echo "The download may be corrupted or tampered with. Aborting installation."
    rm -f l1vm-base-pkg.tar.bz2
    exit 1
fi
echo "Checksum verified OK."

cd ..

What Changed and Why

Line 4-5: Define the expected SHA256 hash as a variable. This hash is the cryptographic fingerprint of the legitimate package. It's hardcoded in the script so it can't be modified by an attacker who compromises the server.

Line 8: Calculate the actual SHA256 hash of the downloaded file. The command tries two approaches:
- sha256 -q (BSD/macOS syntax)
- openssl dgst -sha256 (GNU/Linux fallback)

Lines 9-16: The critical security check. If the calculated hash doesn't match the expected hash, the script:
- Prints a clear error message
- Deletes the suspicious file (preventing accidental installation)
- Exits with error code 1 (preventing further execution)

Line 17: Only if verification succeeds does the script continue.

Why This Specific Approach

  1. Portable: Works on Linux, BSD, and macOS by trying multiple hash commands
  2. Fail-safe: If verification fails, the script stops immediately
  3. Tamper-evident: Prints both expected and actual hashes for debugging
  4. Self-contained: Doesn't require external tools beyond what's in the base system
  5. Clear communication: Users see exactly what failed and why

Prevention & Best Practices

For Installation Scripts

  1. Always verify downloads: Use cryptographic checksums (SHA256 or stronger) before installation
  2. Store hashes separately: Keep known-good hashes in version control, not on the download server
  3. Document hash sources: Explain where hashes come from and how they were generated
  4. Fail securely: If verification fails, abort immediately and clean up partial downloads
  5. Consider GPG signatures: For maximum security, use GPG signatures in addition to checksums

For Package Maintainers

  1. Publish checksums: Include SHA256 hashes on your website alongside downloads
  2. Use signed releases: Create GPG-signed tags in version control
  3. Automate hash generation: Generate hashes during your build process
  4. Monitor for tampering: Set up alerts for unexpected file modifications

Detection and Tools

Static analysis can detect this vulnerability:
- Semgrep: Rules can identify download commands not followed by verification
- ShellCheck: Can flag suspicious patterns in shell scripts
- Custom linters: Enforce checksum verification in installation scripts

Runtime monitoring:
- File integrity monitoring: Tools like aide or tripwire can detect unauthorized changes
- Supply chain scanning: Solutions like syft or grype analyze downloaded artifacts

Security Standards

  • CWE-494: Download of Code Without Integrity Check
  • CWE-295: Improper Certificate Validation
  • OWASP A06:2021: Vulnerable and Outdated Components
  • NIST SP 800-53 SI-7: Software, Firmware, and Information Integrity

Key Takeaways

  1. HTTPS is transport security, not content security: Always verify the content itself, not just the connection
  2. Installation scripts run with elevated privileges: Every download in an installation script is a potential attack vector—verify everything
  3. Checksum verification is non-negotiable for supply chain security: Without it, a compromised server can inject arbitrary code
  4. Fail-safe design matters: The script must abort immediately and cleanly if verification fails, not continue with a warning
  5. Keep hashes in version control: Store known-good hashes alongside your installation script so they can't be modified by a server compromise

How Orbis AppSec Detected This

Source: External URL in install/install-DragonFly.sh:5 — the download destination is controlled by a remote server, making it an untrusted data source

Sink: The download-pkg.sh script call followed immediately by extraction and installation — the downloaded package is executed without verification

Missing control: No integrity verification (checksum or signature) between download and installation

CWE: CWE-494 (Download of Code Without Integrity Check) and CWE-295 (Improper Certificate Validation)

Fix: Added SHA256 checksum verification that compares the downloaded file's hash against a known-good value stored in the installation script before proceeding

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

Supply chain security is one of the most critical—and most overlooked—aspects of secure development. Installation scripts are often the first code that runs on a developer's or user's system, frequently with elevated privileges. This makes them prime targets for attackers.

The vulnerability in install/install-DragonFly.sh demonstrates how a simple omission—failing to verify downloaded packages—can create a critical security risk. By adding SHA256 checksum verification, the fix ensures that only legitimate, unmodified packages are installed.

As you review your own installation scripts, deployment pipelines, and package management processes, remember: never trust a download. Always verify integrity.

References

Frequently Asked Questions

What is insecure package download vulnerability?

It's when software is downloaded and executed without verifying that it hasn't been tampered with or replaced by an attacker. If the download server is compromised, malicious code can be installed.

How do you prevent this in shell scripts?

Always verify downloaded packages using cryptographic checksums (SHA256) or signatures before installation. Store known-good hashes separately and compare before proceeding.

What CWE covers this vulnerability?

CWE-494 (Download of Code Without Integrity Check) and CWE-295 (Improper Certificate Validation) are the primary classifications.

Is HTTPS enough to prevent this vulnerability?

No. While HTTPS protects against network interception, it doesn't protect against server compromise. A compromised server can serve malicious code over HTTPS. Cryptographic verification of the package itself is required.

Can static analysis detect this vulnerability?

Yes. Tools can detect patterns where `curl`, `wget`, or similar download commands are followed directly by extraction or installation without intervening checksum verification.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #8

Related Articles

high

How a named pipe I/O race condition happens in Rust mio and how to fix it

CVE-2024-27308 is a high-severity vulnerability in the Rust `mio` crate (versions prior to 0.8.11) that exposes a race condition in named pipe I/O event handling on Windows. The fix upgrades `mio` from version 0.8.10 to 0.8.11, closing the window for potential exploitation in applications like `rpm-ostree` that depend on async I/O. Because `mio` sits at the foundation of the Tokio async runtime, this flaw has wide blast radius across the Rust ecosystem.

critical

Shell Injection in mkmultidtb.py: How String Concatenation with os.system() Enabled Arbitrary Code Execution

A critical shell injection vulnerability in `scripts/mkmultidtb.py` allowed attackers to execute arbitrary commands during the kernel build process by injecting shell metacharacters into device tree binary (DTB) filenames. The vulnerability was caused by using `os.system()` with string concatenation instead of proper subprocess argument handling. This fix migrates to `subprocess.run()` with argument lists, eliminating the attack surface entirely.

high

Prototype Pollution in defu's Defaults Argument via `__proto__` Key (CVE-2026-35209)

CVE-2026-35209 is a high-severity prototype pollution vulnerability in the `defu` JavaScript library (versions prior to 6.1.5) that allows attackers to inject arbitrary properties onto `Object.prototype` by passing a `__proto__` key in the defaults argument. The vulnerability was present in the `blog-site` project's dependency tree and was resolved by upgrading `defu` to 6.1.5 and adding an explicit `overrides` entry to prevent transitive re-introduction of the vulnerable version.

high

CVE-2026-41676: OpenSSL Bindings Vulnerability Fixed in Rust SDK Cargo.lock

A high-severity vulnerability (CVE-2026-41676) was discovered in the `rust-openssl` crate (version 0.10.73) used in the `apps/rust-sdk` component, as flagged by the Trivy scanner in `Cargo.lock`. The fix upgrades the `openssl` crate from `0.10.73` to `0.10.80` and `openssl-sys` from `0.9.109` to `0.9.116`, closing an exploitable attack surface in production code that handles user-influenced input. Because the Rust SDK sits in the production codebase, any attacker able to reach the OpenSSL code p

critical

Critical Memory Safety Bug: Free of Uninitialized Memory in Rust Telemetry (CVE-2021-29937)

CVE-2021-29937 is a critical memory safety vulnerability in the Rust `telemetry` crate (versions prior to 0.1.3) that allows freeing uninitialized memory, leading to undefined behavior, potential crashes, and possible code execution. The fix involves upgrading the crate from version 0.1.0 to 0.1.3, which patches the unsafe memory handling at the root cause. Despite Rust's reputation for memory safety, this vulnerability demonstrates that `unsafe` code blocks can still introduce serious bugs that

high

How buffer overflow happens in C string operations with strcpy/strncpy and how to fix it

A critical buffer overflow vulnerability in `src/pomoc.c` was discovered where `strncpy()` was used unsafely to copy a socket path into a fixed-size buffer. The fix replaces the dangerous string copy with `snprintf()`, which provides automatic bounds checking and null-termination. This prevents attackers from exploiting the CLI tool through oversized input arguments.