Muzzle is a local workflow runner. It executes scripts that exist on your filesystem.
- Scripts inside
.muzzle/workflows/— you put them there - The
.muzzle/manifests/metadata — you write it - Your local environment — same as running the script directly
- Scripts outside
.muzzle/workflows/— rejected with error - Network-downloaded scripts — Muzzle has no download capability
- User input as shell code — arguments are passed via
"$@"array, nevereval'd - Environment variables in summaries — never printed in default output
Muzzle shell-quotes each workflow argument before invoking the runner command, so every argument is passed as a literal shell word.
This means:
- Arguments are individual strings, not concatenated into a command fragment
- Spaces, quotes, and shell metacharacters in arguments are preserved literally
- No shell injection is possible through Muzzle's argument passing
Note: The workflow script itself is responsible for safely handling its arguments. Muzzle cannot protect against a workflow script that uses eval on its inputs.
Muzzle validates that workflow scripts are inside the expected directory:
- Resolves the script's real path (following symlinks)
- Resolves the
.muzzle/workflows/real path - Rejects execution if the script is not under
.muzzle/workflows/
This prevents:
- Path traversal attacks (
../../etc/passwd) - Symlink escapes to outside directories
- Accidental execution of system binaries
Muzzle scans output for common secret patterns and redacts matching lines from summaries only. Single-line matching is case-insensitive.
| Pattern | Example |
|---|---|
TOKEN= |
export TOKEN=abc123 |
API_KEY= |
API_KEY=sk-1234567890 |
SECRET= |
SECRET=mysecret |
PRIVATE_KEY |
-----BEGIN PRIVATE KEY----- |
Authorization: |
Authorization: Bearer eyJ... |
Bearer |
Bearer abc123 |
password= |
password=hunter2 |
credential= |
credential=admin:pass |
- Summaries (default output): Matching lines replaced with
[REDACTED — secret pattern detected] - Full logs (
.muzzle/logs/): All output preserved unchanged - JSON reports: Error excerpt field is redacted; summary field is your text
- Verbose mode: Terminal output is NOT redacted (you chose to see everything)
- Pattern-based detection is conservative and will miss obfuscated secrets
- Base64-encoded secrets are not detected
- Arbitrary secrets split across multiple lines are not detected unless they match one of the supported key/certificate block markers
- Custom secret formats are not detected
Recommendation: Never print secrets from workflow scripts. Use environment variables and reference them, don't echo them.
Muzzle validates workflow names before execution:
- Length: 1–128 characters
- Forbidden characters:
/,\,..(prevents path traversal) - Empty names: Rejected
Workflow scripts are validated to reside under .muzzle/workflows/ using realpath checks. Scripts outside this directory tree are rejected regardless of symlinks.
The --timeout <ms> flag bounds workflow execution time:
- Default: 300,000ms (5 minutes)
- Minimum: 1,000ms (1 second)
- Maximum: 3,600,000ms (1 hour)
Workflows exceeding the timeout are terminated. This prevents runaway processes from blocking agent workflows indefinitely.
Muzzle does NOT:
- Print environment variables in default output
- Include
envoutput in summaries or reports - Log environment variables to report files
Workflow scripts inherit the caller's full environment. This is the same security model as running the script directly.
Muzzle writes to:
.muzzle/logs/— workflow output capture.muzzle/reports/— markdown and JSON reports.muzzle/state/— session and loop state
Muzzle does NOT write outside .muzzle/ unless the workflow script does so.
Muzzle itself makes no network connections. Network access depends entirely on the workflow scripts you create.
Use the safety.requires_network manifest field to document which workflows need network access.
Muzzle does NOT:
- Auto-commit changes
- Auto-push to remotes
- Modify git configuration
- Run destructive git commands
Any git operations are performed by your workflow scripts, not by Muzzle.
- Review workflow scripts before adding them to
.muzzle/workflows/ - Use
safety.human_approval_recommended: truefor dangerous workflows - Add
.muzzle/logs/and.muzzle/reports/to.gitignore(Muzzle does this oninit) - Never echo secrets in workflow scripts
- Use
--dry-runto preview workflows before first execution - Keep Muzzle updated as security improvements are released
- Trust but verify — Muzzle provides guardrails, not a sandbox
- Kujo native runner with capability-based security (
--untrusted,--allow-shell-exec) - Leash integration for mobile approval of dangerous workflows
- Checksum verification of workflow scripts
- Manifest signature verification
- Workflow script sandboxing (process isolation)