bashka README

The project's README from github.com/dmtrKovalenko/bashka. As one markdown file: README.md.

bashka

A drop-in safety guard for the curl … | bash install pattern. Bashka parses the incoming script, scores it against many different checks, follows forwarded scripts so every layer is analyzed and if it found some unsafety it gives you an easy way to read a script or analyze using your AI agent.

Useage is simple as adding ka after the standard installation script

curl -fsSL https://pyenv.run | bashka

https://github.com/user-attachments/assets/f1a55ede-f1a7-4b9f-a512-d395b30bc53f

Install

Install via bash. One last time.

curl --proto '=https' --tlsv1.2 -fsSL https://bashka.dmtrkovalenko.dev | bash

We guarantee absolute safety of this script! Read it yourself

Or skip bash entirely. The following methods install a release binary or build from source:

Homebrew (macOS and Linux):

brew install bashka

Cargo: from crates.io, or prebuilt via cargo-binstall:

cargo install bashka          # builds from source
cargo binstall bashka         # downloads the release binary

mise

mise use -g github:dmtrKovalenko/bashka   # prebuilt binary from GitHub releases
mise use -g cargo:bashka               # or build from crates.io

Manual: grab bashka-<target> from the releases page, check it against the .sha256 next to it, and drop it on your PATH.

However you installed it, bashka manages itself: bashka update bashka re-runs the installer and bashka remove bashka (or bashka uninstall bashka) deletes the binary, the config and the install registry.

Flags

Findings come in four kinds: 💀 💀 (critically malicious, blocks hard), 🚩 red (dangerous), 🟡 yellow (advisory, never changes the verdict), ✅ green (good-citizen signal).

kind id what it looks for
💀 exfil_destination sends data to webhook.site/Discord/Telegram/ngrok/paste sites, the cloud-metadata IP, or a raw IP (Codecov, Shai-Hulud)
💀 credential_theft reads SSH keys, cloud credentials, .netrc, the keychain
💀 exfiltration environment or secrets sent to the network (env | curl, curl -d "$TOKEN")
💀 reverse_shell backdoors: /dev/tcp, nc -e, socat EXEC, mkfifo pipe-to-shell
🟢 checksum download digest checked: sha256sum -c, $(shasum …) compared, openssl dgst
🟢 cleanup_artifacts trap … EXIT, or rm of a mktemp path
🟢 https_only every download URL uses HTTPS
🟢 install_dir installs into /usr/local/bin or ~/.local/bin
🟢 privilege_escalation (🟢) never escalates; (🟡) uses sudo/doas. Some scripts genuinly need sudo and you will be prompted for it.
🟢 strict_mode set -euo pipefail
🟢 tls_hardening curl pins HTTPS-only and TLS 1.2+ (--proto '=https' --tlsv1.2)
🟢 trusted_domains HTTPS downloads from GitHub, or the same domain the script was fetched from
🟢 verify signature verified: gpg --verify, cosign, minisign, openssl dgst -verify
🔴 anti_forensics hides tracks: HISTFILE=/dev/null, history -c, log truncation, journalctl --vacuum, killing EDR/audit agents
🔴 banned_commands rm -rf /, dd of=/dev/*, mkfs, fork bomb, chmod -R 777
🔴 domain_refs plaintext HTTP, raw-IP hosts, URL shorteners
🔴 env_hijack hijacks auto-run hooks: BASH_ENV/PROMPT_COMMAND/LD_PRELOAD/NODE_OPTIONS --require, sitecustomize.py
🔴 git_hooks repoints git execution: core.hooksPath, core.fsmonitor, alias.x '!cmd', or writes into .git/hooks
🔴 insecure_tls certificate checks off: curl -k, --no-check-certificate, GIT_SSL_NO_VERIFY
🔴 install_name downloads files but nothing names the software (no URL hint, product variable, GitHub repo or bin target); yellow when the script takes the project from its arguments
🔴 install_target downloads files but never names where they are installed
🔴 macos_bypass strips Gatekeeper quarantine (xattr … com.apple.quarantine), tampers with TCC; osascript … hidden answer password phish is 💀
🔴 max_commands more commands than limit
🔴 not_a_script the body is an HTTP redirect stub, an HTML/JSON page, or has no recognizable command (fetch with curl -fsSL)
🔴 obfuscation eval of opaque code (eval "$CMD", eval $(…)), decode-then-execute pipelines
🔴 package_managers pulls code from npm/npx/pip/cargo/go/gem/brew/docker or editor extensions; 🔴 on URL/git/mutable ref/foreign registry/--privileged, yellow on a plain global install
🔴 path_suspicious PATH gains a temp, relative or world-writable directory
🔴 auto_update writes a launcher to disk (shebang heredoc) that downloads by itself every time it runs: self-updating, never reviewed again
🔴 dynamic_download fetches whatever address another command returns (curl "$(get url)", usually a field from a server reply); URLs the script names itself, even with $VERSION filled in, are fine
🔴 remote_exec fetch->exec forward sinks (drives chain following)
🔴 scheduled_tasks schedules code via cron, at, systemd timers, autostart or rc.local
🔴 security_tampering disables firewall/SELinux/AppArmor/Gatekeeper/SIP
🔴 self_extract reads its own bytes ($0) with sed/tail/dd/base64 and pipes the result into a shell
🔴 sensitive_write writes to shell rc files, ~/.ssh, /etc/sudoers, crontab
🔴 staged_installer downloads a program and runs it to do the install; the second stage is opaque to review
🔴 telemetry sends data out (POST/--data, or analytics URLs); notes machine details in the body (uname, hostname) and a UUID saved as a persistent id
🔴 unicode_tricks invisible, bidi, or homoglyph characters in a command name or URL, or a punycode host
🔴 unsafe_rm rm -rf "$VAR/" where the variable may be empty and there is no guard or set -u
🔴 upload_exfil uploads files (curl -T, -F @file, --data @file), copies out via scp/rsync, or DNS-exfil via dig $(…)
🟡 checksum green if checks a digest, yellow if downloads are unverified
🟡 many_downloads fetches from more than limit distinct URLs (default 2)
🟡 mutable_refs downloads from master/main/HEAD/latest instead of a pinned version
🟡 package_repos adds apt/yum/zypper repositories or signing keys
🟡 persistence installs systemd/launchd services or init scripts

CLI

Some of the additional commands

bashka list [--long]                 # table of software installed through bashka
bashka info <name>                   # everything recorded about one package
bashka update <name>                 # re-fetch the recorded installer and run it again
bashka remove <name> [--dry-run]     # delete every recorded binary and created directory, forget the package (alias: uninstall)
bashka flags                         # list every registered flag with its options
bashka config init                   # print default configuration

Install registry

bashka writes a lock file of everything it installed to $XDG_DATA_HOME/bashka/installed.toml (~/.local/share/bashka/installed.toml; BASHKA_LOCKFILE overrides the path). er that exits non-zero leaves no record.

bashka list prints package list, inspired by pacman -Q:

NAME  VERSION        INSTALLED   UPDATED     FILES          SOURCE
mise  2026..1       2026-0-15  -           1              https://mise.run
uv    0.9.2          2026-09-01  2026-09-15  2              https://astral.sh/uv/install.sh
demo  0.0.0-unknown  2026-09-15  -           2 (1 missing)  <stdin>

bashka info <name> (or bashka list --long for all) shows the full record in pacman -Qi style, with each binary and created directory on its own line and missing paths marked.

bashka remove <name> deletes the recorded binaries and created directories, then drops the entry. There is a possibility that bashka couldn't track where the file is installed (which is a red flag) but after your approval it will still be tracked but during the uninstall the binary files wouldn't be deleted.

bashka update <name> fetches the recorded URL again and runs it through the full review with the recorded options and shell arguments.

Configuration

~/.config/bashka/config.toml is deep-merged over the embedded data/defaults.toml.

[flags]
strict_mode     = false
max_commands    = { limit = 200 }
trusted_domains = { additional_domains = ["get.example.com"] }

[interaction]
on_red        = "ask"      # ask | abort | proceed
follow_remote = "always"   # ask | always | never
descend       = "hybrid"   # hybrid | fetch_ahead | shim
max_depth     = 5

[ui]
icons      = "emoji"       # emoji | nerd | ascii
animations = true          # spinners while fetching forwards and on hand-off

Limitations

License

MIT and opensource. Support my work at https://github.com/sponsors/dmtrKovalenko

bashka (dmtrKovalenko/bashka)

Searching Database…

243 ·GitHub
这是干什么的?bashka 是针对 curl | bash 这种安装方式的安全防护工具:它会解析传入的安装脚本,用大量检查项给它打分,并跟踪脚本转发调用的其他脚本,确保每一层都得到分析。
所以我只要在平时的安装命令里把 bash 换成 bashka 就行?是的——用法就是把命令末尾的 bash 换成 bashka:用 curl | bashka 代替 curl | bash。脚本会先被分析,不安全的安装会在执行前被拦截。
bashka 本身怎么安装?可以最后再走一次同样的 curl | bash 方式(“我们保证这个脚本绝对安全!请自行阅读”),或者跳过 bash:macOS 和 Linux 上用 Homebrew,或用 cargo 从 crates.io 安装、cargo-binstall、mise,也可以手动下载发布版二进制文件并用它的 .sha256 校验。
它需要额外装别的东西才能运行吗?不需要——它是一个独立的 Rust 单文件二进制;Homebrew、cargo、mise 或手动下载各自都能独立使用,而且 bashka 自己的更新和卸载也由它自己管理。
如果 bashka 放行了一个脚本,是不是就保证安全了?不是——Bash 是图灵完备的,代码混淆可以绕过静态分析,直接调用 /bin/bash 能绕过 PATH 里安插的垫片,而且服务器在真正运行时下发的字节也可能和预取时不一样。
它能在 Windows 上用吗,还是只有 macOS 和 Linux?macOS 和 Linux——没有提到 Windows 版本。它的检查项都是 Unix 原生的:sudo/doas、systemd/launchd 持久化、macOS Gatekeeper。
它能发现哪类问题?四种严重级别:严重恶意——窃取凭据、反弹 shell、向 Discord/Telegram/webhook.site 外传数据(会硬性拦截);危险——eval 混淆、关闭 TLS 校验、劫持 git hooks、绕过 macOS Gatekeeper;提示——从 main/latest 这类可变引用下载;以及“良好公民”信号,比如校验和验证和 set -euo pipefail。
当脚本看起来不安全时会发生什么?严重问题会硬性拦截。你还可以在决定之前自己阅读脚本,或让你的 AI 智能体来分析它;黄色提示不会改变判定结果。
它会记录自己安装了什么吗?会——bashka 会把它安装的所有内容写入一个锁文件(~/.local/share/bashka/installed.toml)。bashka list 和 bashka info 按照 pacman 的风格打印这些记录,bashka remove 会删除记录在案的二进制文件和目录,bashka update 则重新拉取记录的 URL 并再次走完整的审查流程。
GitHub 以外域名的脚本能被信任吗?可以——默认只信任 GitHub 和脚本本身被拉取的那个域名。额外域名写进 ~/.config/bashka/config.toml,该文件会深合并到内置默认值之上,例如 trusteddomains = { additionaldomains = ['get.acme.io'] }。
What are similar projects?SkillSpector, gh-secure, z, grype, gitleaks, xray, tmuxinator, coreutils
Size
0.3 MB
Stars
243
Age
1mo
Commits · 90 Days