Skip to content

Instantly share code, notes, and snippets.

@kristovatlas
Last active July 28, 2026 02:57
Show Gist options
  • Select an option

  • Save kristovatlas/544b2d7a8314cf21c67e33b5a081695a to your computer and use it in GitHub Desktop.

Select an option

Save kristovatlas/544b2d7a8314cf21c67e33b5a081695a to your computer and use it in GitHub Desktop.
Install Claude Code based on known-good hash instead of curl-bashing; Install Codex with Socket.dev Firewall
#!/usr/bin/env bash
set -euo pipefail
# ── Helpers ──────────────────────────────────────────────────────
info() { printf '\033[1;34m[INFO]\033[0m %s\n' "$*"; }
ok() { printf '\033[1;32m[OK]\033[0m %s\n' "$*"; }
err() { printf '\033[1;31m[ERROR]\033[0m %s\n' "$*" >&2; }
# ── Pre-flight: require npm ──────────────────────────────────────
if ! command -v npm &>/dev/null; then
err "npm is not installed. Please install Node.js/npm first."
exit 1
fi
info "Node $(node -v) / npm $(npm -v)"
# ── Check for Socket Firewall (sfw) ─────────────────────────────
if command -v sfw &>/dev/null; then
ok "Socket Firewall is already installed: $(sfw --version 2>/dev/null || echo 'version unknown')"
else
info "Socket Firewall not found. Installing globally via npm..."
npm i -g sfw
# Verify the install succeeded
if command -v sfw &>/dev/null; then
ok "Socket Firewall installed successfully."
else
err "sfw command not found after install. Check that npm's global bin directory is in your PATH."
err "Hint: npm config get prefix → add <prefix>/bin to your PATH"
exit 1
fi
fi
# ── Clear npm cache (recommended by Socket before first use) ─────
info "Clearing npm cache so sfw can intercept all network requests..."
npm cache clean --force
# ── Run the guarded install ──────────────────────────────────────
info "Running: sfw npm i -g @openai/codex"
sfw npm i -g @openai/codex
ok "Done! @openai/codex installed with Socket Firewall protection."
curl -fsSL https://code.kimi.com/kimi-code/install.sh -o install.sh && checksum="$(sha256sum install.sh | awk '{print $1}')"; if [ "$checksum" = "638927825e96825edbb563de5e0cb06f8a0551c53e026ade8b717b0f25cb83d2" ]; then echo "Checksum matched."; echo "Proceed with installation? (Y/n)"; read response; if [ "$response" = "Y" ] || [ "$response" = "y" ] || [ -z "$response" ]; then bash install.sh && rm -f install.sh; else echo "Installation aborted."; rm -f install.sh; exit 0; fi; else echo "Error: Checksum failed"; exit 1; fi
#!/usr/bin/env bash
set -euo pipefail
PKG="@z_ai/coding-helper"
# ── Helpers ──────────────────────────────────────────────────────
info() { printf '\033[1;34m[INFO]\033[0m %s\n' "$*"; }
ok() { printf '\033[1;32m[OK]\033[0m %s\n' "$*"; }
err() { printf '\033[1;31m[ERROR]\033[0m %s\n' "$*" >&2; }
# ── Pre-flight: require npm ──────────────────────────────────────
if ! command -v npm &>/dev/null; then
err "npm is not installed. Please install Node.js/npm first."
exit 1
fi
info "Node $(node -v) / npm $(npm -v)"
# ── Check for Socket Firewall (sfw) ─────────────────────────────
if command -v sfw &>/dev/null; then
ok "Socket Firewall is already installed: $(sfw --version 2>/dev/null || echo 'version unknown')"
else
info "Socket Firewall not found. Installing globally via npm..."
npm i -g sfw
if command -v sfw &>/dev/null; then
ok "Socket Firewall installed successfully."
else
err "sfw command not found after install. Check that npm's global bin directory is in your PATH."
err "Hint: npm config get prefix → add <prefix>/bin to your PATH"
exit 1
fi
fi
# ── Clear npm cache (recommended by Socket before first use) ─────
# npx resolves through the same cache, so a stale cache means sfw
# never sees the fetch.
info "Clearing npm cache so sfw can intercept all network requests..."
npm cache clean --force
# ── Fetch the package under the firewall ─────────────────────────
# Installing globally (rather than letting npx pull it on every run)
# means the download happens exactly once, inside sfw.
info "Running: sfw npm i -g $PKG"
sfw npm i -g "$PKG"
ok "$PKG installed with Socket Firewall protection."
# ── Install a shell alias so future launches stay gated ──────────
# Without this, typing `npx @z_ai/coding-helper` out of habit runs the
# TUI with unrestricted network access — the firewall only ever covers
# the command it directly wraps. The alias makes the safe form the
# default one.
ALIAS_NAME="zai-helper"
ALIAS_LINE="alias ${ALIAS_NAME}='sfw npx --yes ${PKG}'"
# Write to whichever rc files actually exist; fall back to ~/.bashrc.
RC_FILES=()
for rc in "$HOME/.bashrc" "$HOME/.zshrc"; do
[[ -f "$rc" ]] && RC_FILES+=("$rc")
done
[[ ${#RC_FILES[@]} -eq 0 ]] && RC_FILES=("$HOME/.bashrc")
for rc in "${RC_FILES[@]}"; do
# Match on the alias name, not the whole line, so an older version
# of the alias gets reported instead of silently duplicated.
if grep -q "alias ${ALIAS_NAME}=" "$rc" 2>/dev/null; then
info "An alias named '${ALIAS_NAME}' already exists in ${rc} — leaving it alone."
else
{
printf '\n# Added by install-zai-helper-sfw.sh — run the z.ai TUI behind Socket Firewall\n'
printf '%s\n' "$ALIAS_LINE"
} >> "$rc"
ok "Added '${ALIAS_NAME}' alias to ${rc}"
fi
done
# Aliases are read at shell startup, so this one is not live yet in the
# caller's session.
info "Run 'source ${RC_FILES[0]}' or open a new shell to use: ${ALIAS_NAME}"
# ── Launch, still gated ──────────────────────────────────────────
info "Launching: sfw npx $PKG"
exec sfw npx --yes "$PKG" "$@"
curl -fsSL https://claude.ai/install.sh -o install.sh && checksum="$(sha256sum install.sh | awk '{print $1}')"
if [ "$checksum" = "cde4f1702d3b1695f92b73d26888364e17bca476e17f0fd676484c951d36c125" ]; then
echo "Checksum matched."
echo "Proceed with installation? (Y/n)"
read response
if [ "$response" = "Y" ] || [ "$response" = "y" ] || [ -z "$response" ]; then bash install.sh && rm -f install.sh; else
echo "Installation aborted."
rm -f install.sh
exit 0
fi
else
echo "Error: Checksum failed"
exit 1
fi
curl -fsSL https://claude.ai/install.sh -o install.sh && checksum="$(sha256sum install.sh | awk '{print $1}')"; if [ "$checksum" = "cde4f1702d3b1695f92b73d26888364e17bca476e17f0fd676484c951d36c125" ]; then echo "Checksum matched."; echo "Proceed with installation? (Y/n)"; read response; if [ "$response" = "Y" ] || [ "$response" = "y" ] || [ -z "$response" ]; then bash install.sh && rm -f install.sh; else echo "Installation aborted."; rm -f install.sh; exit 0; fi; else echo "Error: Checksum failed"; exit 1; fi
@kristovatlas

Copy link
Copy Markdown
Author

Today I'm adding the Kimi Code CLI install.sh.
Reviews: Opus 4.8 Max for malicious intent / modification:

Verdict: I found no malicious intent and no signs of tampering. This is a standard trust-on-first-use installer, and actually a more careful-than-average one. The single most sensitive behavior — that it will rename/delete an existing kimi command during migration — is legitimate but worth knowing about (details below).

What the script actually does: detects your OS/arch, resolves a version (pinned or "latest"), downloads a manifest.json and the matching binary from code.kimi.com, verifies the binary's SHA-256 against the manifest, installs it to ~/.kimi-code/bin/kimi, adds that to your PATH, and migrates any old Python kimi-cli shims. That flow matches the official docs exactly, and code.kimi.com/kimi-code/install.sh is the real documented install command from Moonshot AI's own docs and GitHub org — not a look-alike domain.

The things I specifically checked for and didn't find:

No hidden or secondary endpoints. Every network call goes to the one code.kimi.com base URL. No IP addresses, no pastebin/gist/webhook, no base64 -d, no eval, no obfuscation of any kind.
No data exfiltration. Nothing reads SSH keys, cloud credentials, env vars, or browser data. Every network operation is an outbound GET to download; nothing is POSTed anywhere.
Integrity check present. It fetches a checksum, validates its format (^[a-f0-9]{64}$), and refuses to install on mismatch. Many sketchy installers skip this entirely.
No silent privilege escalation. The script never calls sudo itself; it defaults to writing under $HOME. sudo only appears in the optional usage examples.
Good hygiene: set -euo pipefail, a mktemp working dir, and a cleanup trap on exit.

The riskiest part of any installer is anything that deletes or renames files, so I scrutinized the legacy-shim migration (lines ~227–469) closely. It's tightly fenced: it only touches files literally named kimi, only if they're executable, only if the first 4 KB contains the marker kimi_cli, and it explicitly refuses to classify anything inside its own install directory. It resolves symlinks only to sniff the marker but acts on the shim path itself (so it renames/removes the symlink, never the target), checks directory writability before acting, uses mv -- / rm -- to prevent option injection, and always preserves a kimi-legacy fallback. The blast radius is effectively just leftover copies of the old Python CLI. This matches the product's real history — Kimi Code CLI used to be a Python tool installed via uv, and it's now shipping as a single native binary, so cleaning up the old shims is exactly what you'd expect.

Two honest caveats — these are limitations of the approach, not evidence of malice:

Trust-on-first-use. The checksum is served from the same origin as the binary, so it protects against CDN/transport corruption but not against a compromised origin server (an attacker who controlled code.kimi.com would control both). This is inherent to every curl | bash installer, not something specific to this one. You did the right thing saving it and reviewing it rather than piping straight to bash.
This covers the installer, not the binary. The script fetches and installs a closed-source binary; the actual agent code lives there and is out of scope for a shell-script review.

One behavior to be aware of before you run it: the migration will rename your first existing kimi (old Python CLI) to kimi-legacy and delete any duplicate old shims further down your PATH. That's intentional and it keeps a fallback, but if you rely on the old kimi command, know that it's moving.

If you want byte-level certainty that your copy matches what's currently served, you can diff it yourself:

curl -fsSL https://code.kimi.com/kimi-code/install.sh | diff - kimi_install.sh

Two notes on that: a difference isn't necessarily sinister (the hosted script gets updated, so version drift is expected), and I couldn't run this diff from here — my sandbox can't reach kimi.com, and the fetch returns the script as a binary file type rather than text. If you'd prefer to route around direct execution entirely, the documented npm install -g @moonshot-ai/kimi-code path is an alternative that goes through the npm registry's own integrity checks.

virustotal.com: 0/61, but "Matches rule Usage Of Web Request Commands And Cmdlets" and "Matches rule Curl Usage on Linux by Nasreddine Bencherchali (Nextron Systems) at Sigma Integrated Rule Set (GitHub)"
638927825e96825edbb563de5e0cb06f8a0551c53e026ade8b717b0f25cb83d2

@kristovatlas

Copy link
Copy Markdown
Author

Latest CC review:

Review the change to this script for malicious intent:

Nothing in this fragment looks malicious. Walking through the parts that would matter:

The two curl lines are inert. Both sit inside echo string arguments going to stderr — they're guidance text, never executed. The URL is https://claude.ai/install.sh: correct domain spelling, no typosquat, no lookalike TLD, HTTPS. The # pinned-dep-allow comments accurately describe what they're suppressing, which is a good sign rather than a red flag. One thing to confirm in review: that the lint rule those comments suppress is line-scoped, so a suppression can't accidentally cover a genuinely executed fetch elsewhere in the file.

The guard's logic is sound and its direction is privilege-reducing. It fires only when euid is 0 and SUDO_USER is set to a non-root user, so plain root (containers, CI, root-only boxes) is untouched, as the comment claims. ${SUDO_USER:-} and ${CLAUDE_INSTALL_ALLOW_SUDO:-} are properly defaulted for set -u. Nothing here writes files, reads credentials, or touches the network. A change that refuses root is the opposite shape from what an attacker inserts.

Three things worth flagging as ordinary review comments:

  • The suggested override command probably doesn't work on default sudoers. sudo CLAUDE_INSTALL_ALLOW_SUDO=1 bash sets the variable via sudo, which most default configs reject ("you are not allowed to set the following environment variables") unless the sudoers rule carries SETENV or the name is in env_keep. sudo env CLAUDE_INSTALL_ALLOW_SUDO=1 bash is the portable form. Users hitting a hard exit 1 and then a second failure on the documented escape hatch is a bad path.
  • The detection has a known hole. sudo -i or sudo su - resets the environment, dropping SUDO_USER, so a user who takes a root login shell first sails past the guard and installs into /root — exactly the footgun being defended against. Probably acceptable, but it means the check catches the common form, not the class.
  • It's a breaking change for anyone whose automation currently does curl … | sudo bash. Those pipelines will start failing at this new exit 1. Worth a changelog note.

The snippet is cut off at both ends, so I can't see the check that precedes it or confirm the exit 1 that presumably follows these messages. If you want a verdict on the whole change, paste the full diff — in particular anything downstream that resolves $HOME or does the actual download and chmod, since that's where an installer's real risk lives.

Full script confirms it: no malicious intent, and the change is defensive rather than the reverse. Summary of the review, plus a correction to something I said earlier.

The sudo guard. Placement is good — it sits after argument validation and before any network activity or filesystem writes, so it fails early and cheaply. The logic matches the comment: it fires only on euid 0 with a non-root SUDO_USER, leaving plain root untouched. Nothing in the block touches the network, credentials, or disk. One correction to my earlier note: I said the ${SUDO_USER:-} defaults were "properly defaulted for set -u" — the script only sets set -e, so those defaults aren't load-bearing. Harmless either way, but I overstated it. The exit 1 I couldn't see is present and correct.

The rest of the script checks out. Both curl invocations in the error text remain inert (echo to stderr). The real fetches go to downloads.claude.ai over HTTPS, no IP literals or lookalike hosts. The trust chain is sound: binary verified against a SHA256 from manifest.json on the same origin, checksum format anchored to ^[a-f0-9]{64}$, mismatch deletes the file and exits nonzero, chmod +x happens only after verification, and the download is removed afterward. No eval, no base64 blobs, no shell-rc writes, no persistence, no env exfiltration. TARGET reaches the binary as a single quoted argv element and its regex forbids a leading -, so no option or shell injection.

Three defense-in-depth notes, none of them about the change itself:

  • The version regex is anchored only at the front (^[0-9]+\.[0-9]+\.[0-9]+), unlike the fully anchored TARGET check. $version then flows into binary_path="$DOWNLOAD_DIR/claude-$version-$platform", so server-controlled content like 1.2.3/../../../../tmp/x would place and execute the file outside $DOWNLOAD_DIR. It only matters if downloads.claude.ai itself is serving bad content — in which case you have worse problems — but adding (-[^[:space:]]+)?$ costs nothing.
  • No set -o pipefail. It happens to be safe here: every pipeline that could swallow a failure (shasum | cut, jq) yields an empty string that then fails a subsequent check. That's fail-safe by accident rather than by construction.
  • The jq-less manifest parser is brittle but not exploitable. [^}]* can't cross the closing brace of the platform's object, so it can't bind a different platform's checksum, and $platform interpolates from a fixed set of uname-derived literals. It does silently depend on checksum appearing after the platform key.

My two substantive comments on the change stand: sudo VAR=1 bash is rejected by default sudoers without SETENV, so the documented escape hatch will likely fail for the people who need it (sudo env CLAUDE_INSTALL_ALLOW_SUDO=1 bash is portable), and sudo -i/sudo su - drops SUDO_USER and walks straight past the guard into /root.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment