Skip to content

Critical: eval injection in deny.cli wrapper generation #25

Description

@mrjf

Summary

The CLI deny-wrapper generator in packages/runtime/src/band-server.ts builds a bash script that runs eval on patterns derived from a BAND.md's deny.cli field. The patterns are escaped for " but not for $, backticks, or other substitution metacharacters, so a malicious BAND.md can execute arbitrary code at wrapper-generation time inside the Lima VM.

Where

packages/runtime/src/band-server.ts:362-374

The wrapper is emitted as:

DENY_PATTERNS=("user-controlled pattern" ...)
for P in "${DENY_PATTERNS[@]}"; do
  if eval "[[ \"\$FULL_CMD\" == \$P ]]" 2>/dev/null; then
    ...
  fi
done

Reproduction

A BAND.md with deny.cli: ["foo$(id > /tmp/pwned)*"] causes the wrapper script to contain DENY_PATTERNS=("foo$(id > /tmp/pwned)*"). When bash parses the array assignment, the command substitution executes — as the band-server user, before sandboxing.

Threat model

The attacker is anyone who can author a BAND.md the system loads (malicious skill author, compromised dependency, etc.). Code runs as the host VM user, not band-runner — privilege escalation inside the VM.

Fix sketch

Drop eval. Bash already does glob matching in [[ == $P ]] without it:

for P in "${DENY_PATTERNS[@]}"; do
  if [[ "$FULL_CMD" == $P ]]; then ...
done

Alternatively, escape $, backticks, !, and other metacharacters in the pattern array, or restrict deny.cli values to an allowlist of characters at parse time.

Metadata

Metadata

Assignees

Labels

securitySecurity finding

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions