Skip to content

install.cmd: the install.ps1 fallback is fetched unpinned from main, unverified, and left in %TEMP% #237

Description

@fupelaqu

Found reviewing PR #232. Verified against install.cmd as merged.

What happens

When install.ps1 is not next to it, install.cmd downloads one and runs it:

set "PS1_URL=https://raw.githubusercontent.com/SOFTNETWORK-APP/SoftClient4ES/refs/heads/main/install.ps1"
...
set "PS1=%TEMP%\softclient4es-install.ps1"
curl.exe -fsSL -o "%PS1%" "%PS1_URL%"
...
powershell -NoProfile -ExecutionPolicy Bypass -File "%PS1%" %*

The fallback itself is intended and documented — "When install.ps1 is not sitting next to it, it downloads one, so install.cmd on its own is a complete install". Three properties of how it does it are the problem:

  1. The URL is refs/heads/main, unpinned. The file's own comment two lines above says: "A local install.ps1 always wins: a downloaded pair must stay self-consistent, and a released bundle must never be silently mixed with main." An install.cmd shipped in a released bundle, separated from its install.ps1 for any reason, fetches main and produces exactly the mix the comment forbids — silently, since a user who ran the released .cmd has no reason to think they are running main.
  2. No integrity check. The script is fetched over TLS and executed with -ExecutionPolicy Bypass, with nothing verifying it is the file the release intended — no tag, no checksum, no signature.
  3. %TEMP%\softclient4es-install.ps1 is never cleaned up, and it is a fixed, predictable path in a world-writable directory that is then executed with Bypass.

Suggested fix

  • Pin the URL to a tag rather than main — the released .cmd should fetch the install.ps1 of the release it belongs to. The version is already a concept in this script family, so it can be substituted at release time or defaulted to the newest tag.
  • Verify what was downloaded before running it (published SHA-256 alongside the release is the cheapest option that actually closes it).
  • Write to a unique temp path and delete it after the run.

main remains a reasonable default for someone who deliberately fetches install.cmd from main — the point is that the released artefact should not silently do it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions