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

@agnt-gg/nope

v0.1.4

Published

NOPE — Neutralize Operations Prior to Execution. Security guardrails for AI agents with fail-closed execution backends, dangerous-operation rules, secret redaction, prompt-injection scanning, SSRF protection, telemetry, and red-team testing.

Readme

NOPE — Neutralize Operations Prior to Execution

Agent security in one import. Presets to start, fluent builder to customize, one method to scan everything.

npm install @agnt-gg/nope

Quick Start

import { NOPE } from '@agnt-gg/nope';

const nope = NOPE.preset('standard');

nope.check({ command: 'DROP TABLE users;' });
// → { allowed: false, violations: [{ rule: 'db-drop-table', severity: 'critical' }] }

nope.scan(contextText);                                    // prompt injection
nope.scan({ name: 'shell', description: 'Run commands' }); // MCP tool

const safe = nope.wrap(plug.tools);                         // wrap tools

Presets

| Preset | Mode | Threshold | SSRF | Scanners | Telemetry | | ---------- | ------ | --------- | -------- | -------- | --------- | | paranoid | strict | medium | enforced | all on | on | | standard | strict | high | on | off | on | | minimal | strict | high | off | off | off | | audit | audit | low | on + log | all on | on |

Presets accept overrides:

const nope = NOPE.preset('standard', { auth: { verifyToken: myFn } });

Fluent builder

const nope = new NOPE()
  .withRole('admin', 'critical', 'warn')
  .withRole('agent', 'medium', 'strict')
  .withRateLimit('1m', 60, { admin: 200, agent: 30 })
  .withLockout(5)
  .withSSRF({ enforced: true })
  .withScanners({ homograph: true, terminalInjection: true })
  .withTelemetry({ store: 'memory', retention: '7d' })
  .withTrust('@agnt-gg/*');

Core API

check(action, context?)

Test an action against all rules.

nope.check({ command: 'DROP TABLE users;' });
nope.check({ tool: 'exec', params: { command: 'shutdown -h now' } });
nope.check({ code: 'eval(userInput)' });
nope.check({ command: 'shutdown -h now' }, { role: 'developer' });  // identity-aware

wrap(tools)

Wrap tools — inputs checked, outputs sanitized. All layers apply automatically.

const safe = nope.wrap(plug.tools);
for (const t of safe) ai.tool(t.name, t.description, t.input, t.run);

Pipeline: external scanner → built-in rules → identity context → trust level → LLM approval → onBlock → execute → sanitize output.

scan(input)

One method, dispatches by input type:

nope.scan('ignore previous instructions...');          // → prompt injection
nope.scan({ name: 'shell', description: '...' });      // → MCP tool scan
nope.scan({ code: pluginSource });                      // → plugin code scan
await nope.scan({ binary: '/usr/local/bin/tirith' });   // → binary checksum

sanitize(value, toolName?)

Scrub secrets from any value. 17 built-in patterns (OpenAI, Anthropic, AWS, GitHub, Stripe, JWT, PEM, etc.).

const clean = nope.sanitize(toolOutput, 'my-tool');

Configuration

Start with a preset, then layer on what you need. Every feature is opt-in.

Modes & thresholds

new NOPE({ mode: 'strict' })          // block violations (default)
new NOPE({ mode: 'warn' })            // log but allow
new NOPE({ mode: 'audit' })           // silent
new NOPE({ threshold: 'critical' })   // only block critical

Identity & auth

Role-based thresholds, token verification, rate limiting, allow/deny lists, approval memory, lockout.

const nope = NOPE.preset('standard')
  .withRole('admin', 'critical', 'warn')
  .withRole('agent', 'medium', 'strict')
  .withRateLimit('1m', 60, { admin: 200, agent: 30 })
  .withLockout(5)
  .withAuth({
    verifyToken: async (t) => jwt.verify(t, SECRET),
    allowlist: ['user_abc'],
    denylist: ['user_bad'],
  });

await nope.checkWithToken(action, 'eyJhbG...');  // auto-verify + check
nope.recordApproval('user_abc', 'fs-rm-rf', 'always');  // approval memory

SSRF protection

DNS resolution, redirect chain validation, cloud metadata blocking (AWS, GCP, Azure, Alibaba), IPv6 private ranges, custom blocklists, enforced mode.

nope.withSSRF({
  enforced: true,
  customBlocklist: ['evil.internal'],
  allowlist: ['safe-api.com'],
});

await nope.resolveAndCheck('https://suspicious.com');
// → { safe: false, reason: 'DNS rebinding: resolves to 10.0.0.1' }

Execution backends

NOPE never silently falls back to host execution. Callers must select a backend explicitly.

  • Docker is the package's isolation boundary and defaults to no network, dropped capabilities, no-new-privileges, CPU/memory limits, and the pinned alpine:3.20 image.
  • SSH transports a command to a separately administered remote host. SSH is transport, not sandboxing.
  • host-process is explicitly unsafe and runs as the current OS user. It requires acknowledgeHostAccess: true and accepts only an executable plus an argument array—never a shell command string.
  • WASM shell execution is unavailable. Native commands are not WASI modules, and NOPE will not downgrade them to host execution.
const sb = nope.sandbox({
  backend: 'docker', image: 'node:20-slim',
  pidsLimit: 256, readonlyRoot: true, user: 'nobody',
});
await sb.exec('echo hello');

// Trusted host automation only — this is not isolation.
const host = nope.sandbox({
  backend: 'host-process',
  acknowledgeHostAccess: true,
  executable: process.execPath,
  args: ['trusted-script.mjs'],
});
await host.exec();

Scanners

Built-in homograph detection, terminal injection scanning, binary verification.

nope.withScanners({ homograph: true, terminalInjection: true });

Telemetry & dashboard

nope.withTelemetry({ store: 'memory', retention: '7d' });
nope.report();     // → { totalChecks, blocked, riskScore, topViolations, ... }
nope.dashboard();  // → self-contained HTML dashboard

Smart LLM approval

new NOPE({
  llmApprove: async (cmd, violations) => {
    const r = await llm.chat('Safe? ' + cmd);
    return r.includes('safe') ? 'approve' : 'escalate';
  },
});

LLM can only raise severity, never lower. Throws → fail-safe. Verdicts: approve, deny, escalate.

All config options

| Option | Default | Description | | ----------------- | ---------- | ----------------------------------------------------- | | mode | 'strict' | strict blocks, warn logs, audit silent | | threshold | 'high' | Minimum severity to block | | onBlock | -- | Override callback (return true to allow) | | sanitizeOutput | true | Scrub secrets from tool output | | outputPatterns | [] | Additional secret patterns | | onSanitize | -- | Callback when secrets redacted | | llmApprove | -- | Smart LLM approval (approve/deny/escalate) | | externalScanner | -- | External scanner hook (allow/warn/block) | | trustedSources | [] | Glob patterns for trusted tools | | identity | -- | Role-based security profiles | | ssrf | {} | DNS, redirects, enforced mode, blocklists | | telemetry | -- | Event tracking and reporting | | auth | -- | Token verification, rate limiting, allow/deny, lockout | | scanners | {} | Homograph, terminal injection, binary verification |


Built-in Rules

60+ rules across 10 categories. All active by default.

| Category | Rules | Covers | | ------------ | ----- | --------------------------------------------------------- | | filesystem | 9 | rm -rf, format, dd, shred, chmod 777, config deletion | | database | 6 | DROP, TRUNCATE, DELETE/UPDATE without WHERE, GRANT ALL | | system | 7 | shutdown, kill, iptables flush, crontab, passwd, SELinux | | credentials | 15 | API keys (OpenAI, AWS, Stripe, etc.), JWT, PEM, SSH, .env | | injection | 5 | eval, exec, Function constructor, curl|bash, base64 | | exfiltration | 4 | upload secrets, tar pipe, reverse shell, DNS tunneling | | network | 8 | Private IPs, localhost, cloud metadata, IPv6, headers | | git | 4 | force push, hard reset, clean, delete remote branch | | packages | 2 | global install, untrusted npx | | containers | 3 | privileged, rm all, host root mount |

nope.add('no-prod-db', {
  description: 'Block production database writes',
  severity: 'critical',
  category: 'custom',
  match: (a) => /prod/i.test(String(a.params?.database || '')),
});

nope.remove('pkg-global-install');

Capability scoping (v0.1.4)

Most rules detect a dangerous action. A few detect dangerous data. Telling NOPE which is which is the difference between a gate and a nuisance.

By default the matcher walks every string in every argument, so a rule that catches a destructive command also fires on any argument that merely describes one — a note, a search query, a document. Declare what your tool can actually do and NOPE will only apply rules that could possibly matter:

nope.check({
  tool: 'write_file',
  params: { path: 'runbook.md', content: 'Step 2: reboot the host.' },
  capabilities: ['fs-write'],   // what this tool can DO
  sink: { path: 'runbook.md' }, // which args reach an execution sink
});
// -> clean. `content` is data; no shell exists to run it.

nope.check({
  tool: 'execute_shell_command',
  command: 'sudo reboot',
  capabilities: ['shell'],
});
// -> sys-shutdown. This one can actually do it.

Capabilities: shell, code-eval, fs-write, fs-read, sql, http, git, container, any.

Rules opt in with appliesTo. A rule with no appliesTo (or ['any']) is never scoped — it always runs, always against full params. That is how the credentials category stays global: a live API key is a leak wherever it appears, including in a field no shell will ever see.

nope.add('no-prod-writes', {
  description: 'Block writes to production',
  severity: 'critical',
  category: 'custom',
  appliesTo: ['sql', 'shell'],   // irrelevant to a tool that cannot write
  match: (a) => /prod/i.test(String(a.params?.database || '')),
});

Omitting capabilities keeps the old behaviour. Every rule runs against every field, so upgrading loses no coverage until you opt in per tool. An empty array is different from omitting it: capabilities: [] declares a tool with no execution sink at all.

Violations now also report where they matched, which is what makes a false positive obvious on sight:

{ rule: 'sys-shutdown', field: 'params.content', snippet: '…Step 2: reboot the…' }

snippet is deliberately omitted for credentials rules so a secret is never copied into your logs.


Advanced

Guard a single function

const safeExec = nope.guard(async ({ command }) => execSync(command).toString());
await safeExec({ command: 'ls' });       // works
await safeExec({ command: 'shutdown -h now' }); // throws

External scanner

Runs before built-in rules. Verdict is authoritative. Fails open if unavailable.

new NOPE({
  externalScanner: async (action) => ({
    action: (await runBinary(action)).exitCode === 0 ? 'allow' : 'block',
  }),
});

Red team testing

50+ built-in attack vectors with fuzzing.

const r = await nope.redTeam({ attacks: 'all', iterations: 200 });
// → { passed: 187, failed: 13, coverage: { command: { tested: 48, caught: 45 }, ... } }

Consent callback

new NOPE({
  onBlock: async (violations, action) => {
    return await prompt('Allow? (y/n)') === 'y';
  },
});

Sanitization modes (v0.1.0)

sanitize() supports three modes via sanitizeMode (takes precedence over the legacy sanitizeOutput boolean):

| Mode | Behavior | | --- | --- | | 'enforce' (default) | Redact matches in place with [REDACTED:label] | | 'report' | Detect + fire telemetry/onSanitize, return output unmodified — used by the audit preset for true zero-mutation observation | | 'off' | No output scanning |

Binary safety: strings longer than maxSanitizeLength (default 64 KB) or containing long unbroken base64 runs are skipped entirely — redacting inside an encoded image/file payload would silently corrupt it.