Skip to content

Instantly share code, notes, and snippets.

@nilbus
Last active August 11, 2026 16:20
Show Gist options
  • Select an option

  • Save nilbus/ca353bc879f7ad15bd9a802a1e15c8c2 to your computer and use it in GitHub Desktop.

Select an option

Save nilbus/ca353bc879f7ad15bd9a802a1e15c8c2 to your computer and use it in GitHub Desktop.
Security audit findings: beads (bd) CLI - 11-category audit of a vibe-coded Go codebase. No malicious code detected; 4 medium + 6 low conventional findings.

Security Audit Report: beads (bd) CLI

Date: 2026-08-11
Repository: https://github.com/gastownhall/beads
Version: v1.1.2 + 2 weeks of unrelease commits
Commit SHA: 18c24a3ac3e737c34cb478d58ecf3a805a99e996
Scope: Full security audit of a Go CLI tool for issue tracking with Dolt/SQLite backends, git sync, and AI agent integration.
Methodology: glm-5.2-max investigation covering 300+ Go source files, dependency manifests, CI pipelines, and install scripts, searching for unintentional and malicous security issues.


Verdict: No Malicious Code Detected

The 7 malicious-intent categories (backdoors, data exfiltration, obfuscation, supply chain attacks, credential harvesting, trojan functionality, anti-analysis) all returned clean. No backdoors, hidden endpoints, encoded payloads, data exfiltration, credential harvesting, persistence mechanisms, or environment-aware behavior changes were found.


Conventional Vulnerability Findings

Medium Severity (4 findings)

# Category File:Line Issue Recommendation
M1 SQL Injection cmd/bd/doctor/fix/metadata.go:286 dbName from SHOW DATABASES interpolated without backtick escaping. Same file at line 449 has the correct pattern. Apply strings.ReplaceAll(dbName, "", "``")` like line 449
M2 SQL Injection internal/doltserver/doltserver.go:1595,1605 dbName from SHOW DATABASES interpolated in SELECT and USE without escaping. //nolint:gosec comment incorrectly claims it is constant. Escape backticks or validate with isValidIdentifier
M3 SQL Injection cmd/bd/doctor/dolt.go:679 Same unescaped dbName pattern in doctor probes. Same fix as M1
M4 Secrets cmd/bd/federation.go:137 --password/-p flag accepts password as CLI arg, visible in process list. The serve command deliberately avoids this pattern. Consider deprecating --password in favor of interactive prompt only, or env var

Low Severity (6 findings)

# Category File:Line Issue
L1 Secrets internal/configfile/credentials.go:42 Plaintext credentials file (standard pattern like ~/.pgpass, with permission warning)
L2 Secrets internal/storage/dolt/credentials.go:62 AES encryption key stored alongside encrypted data in .beads/ (standard for local CLI tools, 0600 perms, gitignored)
L3 Secrets internal/ado/types.go:101 SecretString type only used for ADO PAT, not other integration tokens (mitigated by masking/redaction)
L4 TLS internal/configfile/external_dolt_config.go:112 InsecureSkipVerify available via opt-in TLSSkipVerify config flag (gated, gosec-suppressed, testing only)
L5 SQL Injection internal/storage/dolt/federation.go:285 AS OF ref interpolation after strict regex validation (^[a-zA-Z0-9_./-]+$) -- Dolt syntax does not support bind params here
L6 Path Traversal internal/beads/beads.go:134 FollowRedirect uses filepath.Join without .. sanitization (mitigated by isPathInSafeBoundary downstream)

Clean Categories (all 11)

Backdoor Detection -- CLEAN

  • 5 hidden cobra commands: all legitimate internal infrastructure (db-proxy-child, codex-hook, cursor-hook, send-metrics, migrate-issues alias)
  • 15 hidden flags: all CLI ergonomics aliases or backwards-compat shims
  • No magic strings, date triggers, username-based triggers, or auth bypasses
  • All HTTP API routes defined in single route table (routes.go:170-733), spec-parity enforced by tests
  • No conditionally-registered or undocumented endpoints

Data Exfiltration -- CLEAN

  • Complete URL inventory: only expected destinations (GitHub, Linear, Jira, GitLab, Notion, ADO, Anthropic, PyPI, beads' own telemetry endpoint)
  • Telemetry sends only command names + HMAC'd machine ID -- never issue content
  • No DNS-based exfiltration (net.LookupHost/TXT/MX not used)
  • Telemetry endpoint hardened against project-level redirect attacks (flusher child drops inherited env vars)
  • All integration sync is user-initiated and expected

Obfuscation -- CLEAN

  • No hardcoded base64/hex strings decoding to URLs, commands, or code
  • All base64 usage: standard auth headers and cursor pagination
  • All hex usage: hash output encoding, test fixtures, CI SHA pins
  • reflect usage: 100% in test files (*_test.go), no production dynamic dispatch
  • unsafe usage: 5 instances, all syscall argument passing (ioctl/fcntl) with gosec annotations
  • No plugin.Open, no go:linkname, no import "C", no string obfuscation

Supply Chain -- CLEAN

  • No typosquatting, no homograph attacks, no suspicious dependencies
  • Zero replace or retract directives in go.mod
  • No vendored code, no local path replacements
  • go.sum: all checksums present and consistent
  • CI: all GitHub Actions pinned with SHA hashes
  • Install scripts verify SHA256 checksums before installing
  • Release pipeline includes SBOM generation and release attestation

Credential Harvesting -- CLEAN

  • Every integration token flows only to its expected API endpoint via Authorization headers
  • No tokens in URL query strings, request bodies to unexpected hosts, or error messages
  • Telemetry args thoroughly scrubbed (passwords, DSN credentials, secret flags)
  • Secret keys stored in config.yaml (not Dolt DB), excluded from dolt push
  • CheckSecretKeyGitSafety() refuses to write secrets to git-tracked config
  • HTTP API settings endpoint redacts secret values via config.IsSecretKey()
  • No InsecureSkipVerify in production paths (only opt-in testing config)

Trojan Functionality -- CLEAN

  • No system file modification (no writes to /etc, /usr, /var, shell configs, SSH keys)
  • No persistence mechanisms (no LaunchAgents, cron jobs, services, self-copying)
  • No sensitive file reads (~/.ssh/id_rsa, ~/.aws/credentials, ~/.kube/config -- zero matches)
  • All process kills target beads' own spawned processes with PID revalidation
  • No network infrastructure modification (no /etc/hosts, firewall, DNS, or proxy changes)
  • All data collection (hostname, machine ID, git user.name) serves legitimate functions

Anti-Analysis -- CLEAN

  • No debugger detection (no ptrace, TracerPid, parent process checks)
  • CI detection (CI=true) only used for non-interactive mode -- standard CLI pattern
  • No analysis tool detection (no strace/gdb/lldb/valgrind/wireshark checks)
  • No timing-based anti-analysis (all time.Sleep calls are legitimate retries/polling)
  • machineid uses HMAC-protected app-scoped ID, not raw hardware ID; opt-out available
  • All /proc reads are for lock diagnostics and orphan cleanup, not tool detection

Command Injection -- CLEAN

  • Every exec.Command call uses separate args, never shell string interpolation
  • Only one sh -c in production code: credential-process helper (by-design, env-var-sourced)
  • Git operations consistently disable hooks (core.hooksPath=) and templates (GIT_TEMPLATE_DIR=)
  • BEADS_DIR validated against isPathInSafeBoundary() with symlink resolution

Path Traversal -- CLEAN

  • isPathInSafeBoundary (SEC-003) rejects system directories and other users' homes
  • safeWorkspacePath uses filepath.Rel to verify containment
  • Atomic file writes via os.CreateTemp (random names, no predictability)
  • Workspace gate rejects symlinked directories and uses O_EXCL for TOCTOU prevention
  • CLI-context file opens (user-supplied @file paths) are acceptable -- user already has FS access

SQL Injection -- CLEAN

  • User data values consistently passed as ? bind parameters across all filter/search/query code
  • Dynamic table/column names sourced from hardcoded constants or validated with strict regex
  • sqlStringLiteral properly escapes ' and \
  • ValidateRef and ValidateConflictTable strictly validate before interpolation

Secrets Handling -- CLEAN

  • No hardcoded secrets found
  • Comprehensive token masking before display and telemetry scrubbing
  • AES-256-GCM encryption for federation peer passwords
  • HTTP API never echoes presented credentials
  • ADO SecretString type prevents accidental serialization of PATs

Security Strengths

  1. Parameterized queries consistently used for all user data values across SQL layer
  2. Constant-time auth comparison (subtle.ConstantTimeCompare) for HTTP API tokens
  3. SHA-256 digests (not plaintext) for auth token storage in memory
  4. Structural secret isolation: secrets in YAML config, not Dolt DB; excluded from sync
  5. Telemetry endpoint pinning: flusher child drops inherited env to prevent hijack
  6. Spec-parity tests for all HTTP API routes
  7. Comprehensive telemetry scrubbing with dedicated test coverage
  8. AES-256-GCM encryption for federation credentials with random keys
  9. SHA-pinned CI actions and checksum-verified install scripts
  10. Git hooks disabled in all internal git operations

Recommended Fixes (Priority Order)

  1. M1 -- cmd/bd/doctor/fix/metadata.go:286: Escape backticks in dbName (same file already has the correct pattern at line 449)
  2. M2 -- internal/doltserver/doltserver.go:1595,1605: Escape backticks in dbName from SHOW DATABASES
  3. M3 -- cmd/bd/doctor/dolt.go:679: Same backtick escaping fix
  4. M4 -- cmd/bd/federation.go:137: Consider deprecating --password flag in favor of interactive prompt only

All four are medium/low severity with limited practical attack surface (the SQL injection findings require a malicious Dolt database name from a synced remote, and the password flag requires local process list access). No critical or high-severity findings.

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