Moron Guard
Moron Guard is a Pi extension. It checks shell commands for destructive operations before Pi runs them. Its TypeScript scanner runs in process and does not invoke an external scanner.
destructive_command_guard inspired the project. Moron Guard is an independent implementation and does not include or depend on that project.
[!WARNING] Moron Guard is a guardrail, not a sandbox. It can miss destructive behavior in generated scripts, unrecognized interpreters, alternate tools, or unknown syntax. Use operating-system or container isolation when you need a security boundary. Review commands before you run them.
What it checks
When enabled, Moron Guard inspects:
bashtool calls made by the model- commands entered through Pi's
!and!!shortcuts - nested commands passed through wrappers such as
sh -c,bash -c,env,sudo,doas,timeout,xargs, andfind -exec - executable substitutions and interpreter payloads, while distinguishing them from quoted, search, and heredoc data
Built-in rules cover destructive filesystem, Git, system, permission, database, container, Kubernetes, cloud, remote, and package-manager operations. Findings include a rule ID, severity, confidence, evidence, and remediation.
The evaluator does not execute the command that it checks. Its decision path does not start subprocesses or use network and filesystem probes. It rejects input over 256 KiB by default and bounds nested parsing. It returns an error for malformed or opaque dynamic shell syntax. The Pi extension blocks those errors by default.
Requirements
- Node.js 22 or later
- Pi
- Git for installation from this repository
Install
Review the source before installing: Pi extensions run with your full user permissions.
pi install npm:moron-guard@0.1.0
Versioned installs stay pinned. You can also install the matching Git tag after reviewing its source:
pi install git:github.com/Jeecabs/moron-guard@v0.1.0
Restart Pi after installation. To try the extension without adding it to Pi's settings:
pi -e npm:moron-guard@0.1.0
To remove it:
pi remove npm:moron-guard
Commands
/moron status
/moron doctor
/moron rules
/moron explain git reset --hard HEAD
/moron reload
/moron clear-cache
/moron off
/moron on
The guard starts enabled. /moron off disables it for the current session. Pi stores this state in the session history. /moron on enables the guard again.
Configuration
Moron Guard reads global configuration first, then project configuration:
~/.pi/agent/moron-guard.json(or$PI_AGENT_DIR/moron-guard.json).pi/moron-guard.jsonin the current project
The legacy project path .moron-guard.json is accepted when .pi/moron-guard.json does not exist. Set MORON_GUARD_CONFIG to use one explicit file instead. Environment variables override file values. Run /moron reload after changing configuration.
{
"enabled": true,
"mode": "enforce",
"failClosed": true,
"userBash": true,
"categories": ["filesystem", "git", "database"],
"allow": ["git status"],
"maxDepth": 8,
"maxCommandBytes": 262144
}
Modes:
enforce: block deny decisions and evaluation errors whenfailClosedis trueaudit: evaluate commands without blocking themoff: skip evaluation
By default, project configuration can only strengthen the core switches. It can set enabled, mode: "enforce", failClosed, or userBash to safe values. Moron Guard ignores project allowlists, category filters, parser limits, and weakening switch values. Set MORON_GUARD_ALLOW_PROJECT_CONFIG=1 only when you trust the project. This setting applies its complete configuration. Global configuration, explicit configuration, and environment variables remain trusted policy sources.
Environment variables
| Variable | Purpose |
|---|---|
MORON_GUARD_CONFIG |
Path to one explicit config file |
MORON_GUARD_ENABLED |
Enable or disable the guard |
MORON_GUARD_MODE |
enforce, audit, or off |
MORON_GUARD_FAIL_CLOSED |
Block evaluation errors |
MORON_GUARD_USER_BASH |
Inspect Pi ! and !! commands |
MORON_GUARD_CATEGORIES |
Comma-separated rule families |
MORON_GUARD_ALLOW |
Semicolon-separated exact normalized commands |
MORON_GUARD_MAX_DEPTH |
Nested parse depth from 1 through 32 |
MORON_GUARD_MAX_COMMAND_BYTES |
UTF-8 input limit from 1 KiB through 1 MiB |
MORON_GUARD_ALLOW_PROJECT_CONFIG |
Trust and apply all project configuration fields |
Boolean environment values accept 1, true, on, or yes, and 0, false, off, or no, without regard to case.
Allowlisting uses exact normalized-command matching. It does not evaluate regular expressions. Keep allowlists narrow: an allowlisted command bypasses findings for that command.
Built-in rule families
filesystem: recursive removal, secure deletion, andfind -deletegit: hard reset, clean, path restore or checkout, stash deletion, branch deletion, force push, and recovery-data expirationsystem: block-device writes or formatting, disk erase, service stop, and destructive inline interpreter behaviorpermissions: broad recursive or world-writable permission changesdatabase: destructive SQL and database CLI operationscontainers: destructive Docker and Compose operationskubernetes: broad namespace or resource deletioncloud: recursive object deletion and destructive provider commandsremote:rsyncdeletionpackage-manager: destructive cache, store, and publication operations
Use /moron rules for the enabled family names and /moron explain <command> to inspect a decision without running the command.
Host-independent API
You can use the evaluator without Pi:
import { createGuard } from "moron-guard";
const guard = createGuard({ context: { cwd: process.cwd() } });
const decision = guard.evaluate("git reset --hard HEAD");
if (decision.enforce) {
throw new Error(`Command rejected: ${decision.action}`);
}
A decision has an action of allow, deny, or error, an enforce compatibility boolean, source: "native", and structured diagnostics. Treat error as blocking unless your host explicitly implements a fail-open policy.
Development
git clone https://github.com/Jeecabs/moron-guard.git
cd moron-guard
pnpm install --frozen-lockfile
pnpm check
pnpm test
pi -e ./src/index.ts
The tests parse and evaluate command strings. They do not execute candidate commands. See CONTRIBUTING.md before you submit a change. Maintainers should follow RELEASING.md when they publish a version.
Security and support
Report vulnerabilities according to SECURITY.md. Use SUPPORT.md for usage questions and ordinary bug reports.
License
See LICENSE.