Suite Utils

Security

What the plugin runs on your machine, why it ships with no npm dependencies, what it can reach, and how to check the code yourself.

On this page

The plugin runs on your machine with your user's permissions, every time Claude calls NetSuite. This page covers what that code is, what it can touch, and how to check it before you trust it.

No third-party code at runtime

The plugin has no runtime dependencies. What runs is one file, scripts/nsx.mjs, built from the TypeScript in src/ and committed to the repository. It imports nothing but Node's own built-in modules:

ModuleWhat the plugin uses it for
node:fs, node:path, node:osReading and writing the cache, saved results and audit log in the plugin's data directory
node:cryptoHashing inputs, so a write preview can be matched to the exact call
node:zlibCompressing the .xlsx file when you export a result to Excel
node:child_processOne call, git check-ignore, to warn you when an export lands in a folder git would commit. It has a 3-second timeout

This matters because of how supply-chain attacks work. A typical Node tool pulls in dozens or hundreds of packages. If one of them is compromised upstream, the next install or update runs the attacker's code with the same access as the tool. Here that access would include your NetSuite results and the hooks that decide which calls go through. With no packages in the runtime, there's no upstream code to swap: what runs is what's in the repository.

What happens at install

Claude Code copies the repository into its plugin cache. When a plugin has a package.json and a lockfile, Claude Code also runs npm ci --ignore-scripts in that copy. For this plugin that step installs nothing. Every package in package.json is a development tool, and the repository's .npmrc sets omit=dev, so the install resolves to zero packages and nothing is downloaded from npm. The hooks then run the committed bundle with node.

Build tools

Three packages are used to build and test the plugin, and never at runtime or install: esbuild bundles src/ into scripts/nsx.mjs, typescript checks types, and @types/node provides Node's type definitions. They're pinned in package-lock.json, and only a developer who runs npm ci --include=dev gets them.

A compromised build tool could, in principle, change what goes into the bundle. That's why the bundle is built once and committed, not built on your machine: every change to it shows up as a diff in the repository. CI rebuilds it from src/ on every push to main and every pull request, and fails if the result differs from the committed file by a single byte. It also runs the bundle on Node 18, 20 and 22, on Linux and macOS.

What the code can reach

  • The network: nothing. The plugin contains no HTTP, socket or fetch code. The NetSuite AI Connector is still the only thing that talks to NetSuite, over the connection and OAuth you set up for it. The plugin never reads or changes that configuration.
  • Files: its own data directory, under ~/.claude/plugins/data/. It writes to your project only when you export something, to ./exports/ or a path you give it.
  • Other processes: one. The git check-ignore call above.
  • Tool calls: only ns_* connector calls. The hooks are registered for mcp__.*__ns_.* and a session start. They don't see your other tools.

The full list of what's stored and for how long is on Data and privacy.

How writes are guarded

Creates and updates are blocked by default. With writes on, each one needs a preview, a call with the same input, and your approval in Claude Code's permission prompt. The details are on Writes and approvals. A few rules sit underneath that:

  • Unknown tools count as writes. Only NetSuite tools the plugin knows to be read-only skip the write guard. A new tool the connector adds goes through read_only, the preview and your approval, and the prompt says the tool is unknown.
  • A write the plugin can't check is blocked. If the hook itself fails, a read goes through unchanged and a write is denied.
  • Claude can't turn writes on. nsx config set read_only=false refuses to run from anything Claude Code starts. It isn't a hard lock, because the setting lives in a plain settings.json. Every write still needs your approval either way.
  • The approval prompt shows exact changes. The diff is rebuilt from the input being sent and compares full field paths, so a change can't hide behind a field with the same name.
  • Cache paths stay inside the data directory. Section names are validated and every cache path is checked, so a crafted record type can't write a file elsewhere.
  • Exports can't run formulas. In CSV exports, a text cell that starts with =, +, -, @, a tab or a carriage return gets a leading ', so a spreadsheet shows it as text.

Where the plugin can't protect you

In Cowork and claude.ai, plugin hooks don't run. There's no write guard there, so limit writes through the connector role's permissions in NetSuite. The same role is also your limit everywhere else: the plugin can block a call, but it can't grant access the role doesn't have.

Check it yourself

Everything above can be checked from a clone of the repository:

# Every import in the shipped bundle: only node: built-ins
grep -oE 'from "[^"]+"' scripts/nsx.mjs | sort -u

# Run the install step Claude Code runs, then list what it installed: (empty)
npm ci --ignore-scripts && npm ls --all --omit=dev

# Rebuild from source and confirm it matches the committed bundle
npm ci --include=dev && npm run build && git diff --exit-code scripts/nsx.mjs

# What Claude Code runs, and on which tools
cat hooks/hooks.json

Reporting a vulnerability

Email [email protected]. Please don't open a public issue for a security bug. The site's security page covers how we handle reports.

Install su-ns-harness

Run both inside Claude Code, then /reload-plugins. Version 0.5.1, free and open source.

  1. /plugin marketplace add suiteutils/suiteutils-netsuite-claude-harness
  2. /plugin install su-ns-harness@suiteutils

Page last updated 2026-09-28. NetSuite is a trademark of Oracle. Claude is a trademark of Anthropic. Suite Utils is not affiliated with either.