Inventory what matters on developer machines—tools, configs, and metadata about secrets—to improve org supply‑chain security without exfiltrating payloads.
Bagel is a cross‑platform CLI that inspects developer workstations (macOS, Linux, Windows) and produces a structured report of:
For detailed documentation on each probe and detector, see the Bagel docs site.
Looking for more? If you want a more powerful, enterprise-grade version with the ability to deploy at scale and collect posture information across your entire developer laptop fleet, have a look at the BoostSecurity Developer Endpoint Protection (DEP) product.
Modern supply‑chain risk often lands on developer endpoints (malicious packages, misconfig creds, weak key hygiene). Bagel standardizes visibility so security teams can:
http.sslVerify=false, ForwardAgent yes, plaintext creds files, unencrypted SSH keys)..env files, and config files.--strict.credential.helper=store, http.sslVerify=false, custom core.sshCommand with non‑standard binaries, dangerous protocols, fsck disabled..npmrc, strict-ssl=false, HTTP (non‑HTTPS) registries.ForwardAgent yes, StrictHostKeyChecking=no, permissive file modes..env files, or shell command history.Download the latest release from GitHub Releases.
macOS:
# Intel Mac
curl -sL https://github.com/boostsecurityio/bagel/releases/latest/download/bagel_Darwin_x86_64.tar.gz | tar xz
sudo mv bagel /usr/local/bin/
# Apple Silicon
curl -sL https://github.com/boostsecurityio/bagel/releases/latest/download/bagel_Darwin_arm64.tar.gz | tar xz
sudo mv bagel /usr/local/bin/
Homebrew:
brew install bagel
Linux:
# x86_64
curl -sL https://github.com/boostsecurityio/bagel/releases/latest/download/bagel_Linux_x86_64.tar.gz | tar xz
sudo mv bagel /usr/local/bin/
# ARM64
curl -sL https://github.com/boostsecurityio/bagel/releases/latest/download/bagel_Linux_arm64.tar.gz | tar xz
sudo mv bagel /usr/local/bin/
Windows:
Download bagel_Windows_x86_64.zip from the releases page, extract it, and add it to your PATH.
Invoke-WebRequest -Uri "https://github.com/boostsecurityio/bagel/releases/latest/download/bagel_Windows_x86_64.zip" -OutFile "bagel.zip"
Expand-Archive -Path "bagel.zip" -DestinationPath "."
Requires Go 1.25 or later.
git clone https://github.com/boostsecurityio/bagel.git
cd bagel
go build -o bagel ./cmd/bagel
bagel version
bagel scan
This scans your workstation and outputs findings to stdout in JSON format.
| Flag | Description |
|---|---|
--format, -f |
Output format: json (default), table |
--output, -o |
Write output to a file instead of stdout |
--strict |
Exit with code 2 if any findings are detected |
--no-cache |
Bypass file index cache and force rebuild |
--no-progress |
Disable progress bars |
--verbose, -v |
Enable verbose (debug) logging |
--config |
Path to configuration file |
--disable-version-check |
Disable the once-per-day check for newer bagel releases (env: BAGEL_DISABLE_VERSION_CHECK, config: disable_version_check) |
# Save report to a file
bagel scan -o report.json
# Table output for quick review
bagel scan -f table
# CI gate: fail the build if findings exist
bagel scan --strict
# Debug a specific scan
bagel scan --verbose --no-progress
Bagel uses a YAML configuration file. It looks for bagel.yaml in these locations (in order):
--config./bagel.yaml)~/.config/bagel/bagel.yaml on Unix, %APPDATA%\bagel\bagel.yaml on Windows)version: 1
probes:
git:
enabled: true
ssh:
enabled: true
npm:
enabled: true
env:
enabled: true
shell_history:
enabled: true
cloud:
enabled: true
jetbrains:
enabled: true
gh:
enabled: true
ai_credentials:
enabled: true
ai_chats:
enabled: true
privacy:
redact_paths: []
exclude_env_prefixes: []
output:
include_file_hashes: false
include_file_content: false
All probes are enabled by default. To disable a probe, set enabled: false.
By default, bagel reaches out at most once every 24 hours to check whether a newer release is available. The request reports the current bagel version, an anonymous instance identifier persisted under the platform config directory (~/.config/bagel/version-check.yaml on Unix, %APPDATA%\bagel\version-check.yaml on Windows), and a count of CLI invocations since the last check. No scan, host, or finding data is sent. To disable, use any of:
--disable-version-check flagBAGEL_DISABLE_VERSION_CHECK=1 environment variabledisable_version_check: true in bagel.yaml{
"metadata": {
"version": "0.1.0",
"timestamp": "2026-02-10T12:00:00Z",
"duration": "1.234s"
},
"host": {
"hostname": "dev-laptop",
"os": "darwin",
"arch": "arm64",
"username": "dev",
"system": {
"os_version": "15.3",
"kernel_version": "Darwin 25.2.0",
"cpu_model": "Apple M1",
"cpu_cores": 8,
"ram_total_gb": 16
}
},
"findings": [
{
"id": "git-ssl-verify-disabled",
"probe": "git",
"severity": "high",
"title": "Git SSL Verification Disabled",
"message": "Git is configured to skip SSL certificate verification...",
"path": "git-config:http.sslverify"
},
{
"id": "ssh-private-key-rsa",
"probe": "ssh",
"severity": "critical",
"title": "Unencrypted SSH Private Key Detected (RSA)",
"message": "An unencrypted RSA SSH private key was detected...",
"path": "file:/Users/dev/.ssh/id_rsa"
}
]
}
Each probe declares its scope (user/system), paths touched, env vars read, and risk rules it can emit.
| Probe | Description | What it checks |
|---|---|---|
git |
Git configuration security | SSL verification disabled, SSH config issues (StrictHostKeyChecking, UserKnownHostsFile), plaintext credential storage (credential.helper=store), dangerous protocols (ext, fd, file), fsck disabled, proxy settings, custom hooks path |
ssh |
SSH configuration and key security | StrictHostKeyChecking=no, UserKnownHostsFile=/dev/null, ForwardAgent=yes, private key file permissions, unencrypted private keys |
npm |
NPM/Yarn configuration | .npmrc and .yarnrc files: strict-ssl=false, HTTP (non-HTTPS) registries, always-auth settings |
env |
Environment variables and dotfiles | Environment variables, shell config files (.bashrc, .zshrc), .env files for embedded secrets |
shell_history |
Shell history files | .bash_history, .zsh_history for secrets in command history |
cloud |
Cloud provider credentials | AWS (~/.aws/config, ~/.aws/credentials), GCP (~/.config/gcloud/), Azure config files |
jetbrains |
JetBrains IDE configuration | JetBrains IDE workspace files and configuration for embedded secrets |
gh |
GitHub CLI | GitHub CLI authentication tokens and configuration |
ai_cli |
AI CLI tools | Credential files and chat logs for Gemini, Codex, Claude, and OpenCode |
| Detector | Description | Patterns detected |
|---|---|---|
github-token |
GitHub authentication tokens | Classic PAT (ghp_), Fine-grained PAT (github_pat_), OAuth (gho_), App User-to-Server (ghu_), App Server-to-Server (ghs_), Refresh Token (ghr_) |
npm-token |
NPM authentication tokens | NPM auth tokens (npm_*) |
ai-service |
AI service API keys | OpenAI (sk-), Anthropic (sk-ant-api03-, sk-ant-admin01-), Hugging Face (hf_, api_org_) |
http-authentication |
HTTP auth credentials | Bearer tokens, Basic Auth headers, API key headers (X-API-Key, etc.), Basic Auth in URLs (http://user:pass@host) |
ssh-private-key |
SSH private keys | RSA, DSA, EC, OPENSSH, PKCS8 keys; detects encrypted vs unencrypted |
cloud-credentials |
Cloud provider credentials | AWS Access Key ID (AKIA*, ASIA*, etc.), GCP API Key (AIza*), Azure Storage Account Key |
generic-api-key |
Generic secrets | High-entropy strings matching common secret patterns (uses Shannon entropy analysis) |
jwt |
JSON Web Tokens | JWT tokens (eyJ prefix with standard JWT structure) |
| OS | Support |
|---|---|
| macOS (Intel & Apple Silicon) | Full support |
| Linux (x86_64 & ARM64) | Full support |
| Windows (x86_64) | Full support with platform-specific file paths and PowerShell history |
All probes work cross-platform with appropriate path handling for each OS.
Fork addition -- not in upstream Bagel.
bagel scrub removes credentials from AI CLI session logs and shell history files, replacing them with [REDACTED-<type>] markers while preserving conversation context.
# Scan and interactively confirm (default)
bagel scrub
# Skip prompt, apply immediately
bagel scrub --yes
# Scan only, no modifications
bagel scrub --dry-run
# Scrub without grace period (includes recent files)
bagel scrub --yes --grace-minutes 0
# Scrub a single file
bagel scrub --yes --file ~/.claude/projects/foo/abc123.jsonl
| Flag | Default | Description |
|---|---|---|
--yes / -y |
false |
Skip confirmation prompt and apply changes |
--dry-run |
false |
Scan and report only, do not modify files |
--grace-minutes |
60 |
Skip files modified within this many minutes |
--file |
Scrub a single file instead of all eligible files |
Targets:
- ~/.claude/projects/**/*.jsonl -- Claude Code session logs
- ~/.claude/projects/**/*.txt -- Claude Code tool results
- ~/.codex/sessions/**/*.jsonl -- Codex CLI session logs
- ~/.gemini/tmp/*/chats/*.json -- Gemini CLI chat logs
- ~/.local/share/opencode/**/*.json -- OpenCode session logs
- ~/.bash_history -- Bash shell history
- ~/.zsh_history -- Zsh shell history
- ~/.sh_history -- Generic shell history
- ~/.local/share/fish/fish_history -- Fish shell history
Recommended workflow:
1. bagel scan -f table -- assess your exposure
2. bagel scrub --yes -- clean up
3. bagel scan -f table -- verify reduction
4. Rotate any credentials that were found
bagel scan --strict in your pipeline to fail builds when findings are detected.0 – success, no findings detected (or --strict not set)1 – runtime error2 – findings detected (when using --strict)Does it read my secrets? No. It only gathers metadata and security‑relevant flags.
Is it noisy? Probes are read‑only, batched, and time‑boxed to keep scans under a minute on typical dev machines.
$ claude mcp add bagel \
-- python -m otcore.mcp_server <graph>