npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

opencode-damage-control

v1.5.0

Published

OpenCode plugin that blocks dangerous commands and protects sensitive paths

Readme

opencode-damage-control

Defense-in-depth security plugin for OpenCode. Blocks dangerous commands and protects sensitive files before they execute.

CI npm version npm downloads License: MIT Built with OpenCode Zero Dependencies

Documentation · Issues · Contributing · Security


Why

AI coding agents have shell access, file read/write, and broad autonomy. A single bad command -- whether from a hallucination, prompt injection, or honest mistake -- can:

  • rm -rf / your filesystem
  • DROP TABLE your production database
  • Leak ~/.ssh keys or ~/.aws credentials
  • git push --force over your team's work
  • terraform destroy your infrastructure

This plugin intercepts every tool call and either blocks or asks for confirmation before dangerous ones run.


Quick Start

Add to your opencode.json:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["opencode-damage-control"]
}

Restart OpenCode. Done -- all protections are active with zero configuration.


What It Protects

144 Command Patterns

56 hard-blocked, 88 require confirmation. Covers system destruction (rm -rf /, fork bombs, dd), SQL (DROP TABLE, DELETE FROM, TRUNCATE), git (--force push, filter-branch, stash clear), cloud infrastructure (AWS, GCP, Azure, Terraform, Pulumi), Docker/Kubernetes, databases (Redis, Postgres, MySQL, MongoDB), hosting platforms (Vercel, Netlify, Heroku, Fly.io, Cloudflare, Firebase, Serverless), process/system manipulation (crontab -r, systemctl, iptables, launchctl), and Windows-specific commands (del /s /q, rd /s /q, diskpart, reg delete, bcdedit, PowerShell Remove-Item, Stop-Service, Uninstall-Package).

Shell wrapper unwrapping: Commands wrapped in bash -c "...", sh -c "...", python -c "...", cmd /c "...", powershell -Command "...", pwsh -c "...", env bash -c "...", etc. are automatically unwrapped and inspected. Nested wrappers are handled recursively.

Full pattern list →

103 Protected Paths

Three-tier protection system for sensitive files:

| Level | Read | Write | Delete | Examples | |-------|------|-------|--------|----------| | zeroAccess | Block | Block | Block | ~/.ssh, ~/.aws, .env*, *.pem | | readOnly | Allow | Block | Block | /etc/, lock files, node_modules/, dist/ | | noDelete | Allow | Allow | Block | .git/, LICENSE, Dockerfile, CI configs |

Full path list →

Actions

| Action | Behavior | When | |--------|----------|------| | block | Hard block. Tool never executes. | Catastrophic commands (rm -rf /, DROP TABLE, terraform destroy) | | ask | User sees confirmation dialog. | Risky-but-valid commands (git reset --hard, rm -rf, DELETE ... WHERE) |


How It Works

flowchart TD
    CALL["OpenCode Tool Call"]

    CALL --> EXEC["bash / shell / cmd"]
    CALL --> READ["read / glob / grep"]
    CALL --> WRITE["edit / write / create"]

    EXEC --> UNWRAP["Unwrap Shell Wrappers"]
    UNWRAP --> PP["Pattern + Path Check"]
    READ --> PC1["Path Check"]
    WRITE --> PC2["Path Check"]

    PP --> |block| THROW["THROW (hard block)"]
    PP --> |ask| STASH["STASH by callID"]
    PP --> |no match| ALLOW1["ALLOW"]

    PC1 --> |zeroAccess| BLOCK1["BLOCK"]
    PC1 --> |otherwise| ALLOW2["ALLOW"]

    PC2 --> |zeroAccess / readOnly| BLOCK2["BLOCK"]
    PC2 --> |otherwise| ALLOW3["ALLOW"]

    STASH --> PERM["permission.ask hook"]
    PERM --> DIALOG["CONFIRM DIALOG"]

    style THROW fill:#dc2626,color:#fff,stroke:#991b1b
    style BLOCK1 fill:#dc2626,color:#fff,stroke:#991b1b
    style BLOCK2 fill:#dc2626,color:#fff,stroke:#991b1b
    style DIALOG fill:#f59e0b,color:#000,stroke:#d97706
    style ALLOW1 fill:#16a34a,color:#fff,stroke:#15803d
    style ALLOW2 fill:#16a34a,color:#fff,stroke:#15803d
    style ALLOW3 fill:#16a34a,color:#fff,stroke:#15803d

Hook 1: tool.execute.before -- inspects every tool call. Matches with block throw immediately. Matches with ask are stashed by callID and proceed to the permission system. Protected paths are enforced based on their tier and the operation type.

Hook 2: permission.ask -- looks up stashed matches and forces output.status = 'ask', ensuring the user sees the confirmation dialog even if their permission config would normally auto-allow.


Configuration

Everything works out of the box. To customize, create a damage-control.json in either or both locations:

| Location | Scope | |----------|-------| | ~/.config/opencode/damage-control.json | Global (all projects) | | .opencode/damage-control.json | Project (this repo only) |

Both optional. Project merges on top of global. Invalid config logs warnings and uses defaults.

Schema

{
  "patterns": {
    "add": [
      { "pattern": "my-dangerous-cmd", "reason": "Custom block", "action": "block" }
    ],
    "remove": ["SQL DROP TABLE"],
    "override": {
      "Recursive delete from root": "ask"
    }
  },
  "paths": {
    "add": [
      { "path": "~/.my-secrets", "level": "zeroAccess" }
    ],
    "remove": ["~/.npmrc"],
    "override": {
      "~/.docker": "none"
    }
  }
}

Operations

| Operation | What it does | |-----------|-------------| | add | Append new patterns/paths after defaults | | remove | Remove by exact reason (patterns) or path (paths) | | override | Change action or level. Use "none" to unprotect a path. |

Processing order: defaults → remove → override → add.

When both global and project configs exist: add arrays concatenate, remove arrays union, override objects shallow-merge (project wins).

Examples

Relax a block to ask:

{ "patterns": { "override": { "Terraform destroy": "ask" } } }

Add a custom pattern:

{
  "patterns": {
    "add": [{ "pattern": "prod-db-wipe", "reason": "Wipes production DB", "action": "block" }]
  }
}

Unprotect a path:

{ "paths": { "override": { "~/.npmrc": "none" } } }

What Happens

When something is blocked

The AI agent sees an error and adjusts:

DAMAGE_CONTROL_BLOCKED: SQL DROP TABLE

Command: DROP TABLE

When something triggers a confirmation

OpenCode shows the standard permission dialog:

damage-control flagged: git reset --hard

[once]  [always]  [reject]

Limitations

  • Substring matching for paths. A command that merely mentions a protected path (e.g., in a comment) will be blocked.
  • Shell only, not subprocesses. Inspects command strings passed to bash/shell/cmd. Cannot inspect commands spawned by scripts (but does unwrap bash -c, python -c, etc.).
  • Pattern ordering matters. First match wins. Specific patterns are ordered before generic ones.
  • Ask requires permission system. The permission.ask hook forces the dialog even if the user's config auto-allows, but exact UX depends on OpenCode version.

Development

git clone https://github.com/whjvenyl/opencode-damage-control.git
cd opencode-damage-control
npm install
npm run build    # output in dist/
npm test         # 454 tests

Architecture

src/
  patterns.ts        144 patterns, 103 paths, shell unwrapping, matching helpers
  config.ts          Config loading, validation, merging
  index.ts           Plugin entry point (2 hooks)
  patterns.test.ts   428 pattern + unwrapping tests
  config.test.ts     26 config tests

| Module | Exports | |--------|---------| | patterns.ts | DEFAULT_PATTERNS, DEFAULT_PROTECTED_PATHS, matchPattern(), checkPathProtection(), checkShellPathViolation(), unwrapShellCommand() | | config.ts | loadConfig(), applyConfig(), DamageControlConfig | | index.ts | DamageControl plugin -- loads config at init, returns tool.execute.before + permission.ask hooks |


Contributing

See CONTRIBUTING.md for setup, architecture, and PR conventions.

For security vulnerabilities, see SECURITY.md.


Acknowledgments

Based on the concept from claude-code-damage-control by @disler. Reimplemented as a native OpenCode plugin with zero runtime dependencies.


License

MIT