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

pii-masker

v1.0.1

Published

Mask PII before sending content to AI chatbots (Cursor hooks, CLI, VS Code)

Downloads

206

Readme

PII Masker

Mask personally identifiable information (PII) before content is sent to AI chatbots. Use it in Cursor, VS Code (or any VS Code–based IDE), or as a CLI in your pipeline.

What gets masked

  • Email addresses
  • Phone numbers (US and international formats)
  • Social Security Numbers (US)
  • Credit card–like numbers (4×4 digits)
  • IPv4 addresses
  • AWS access keys (AKIA...)
  • API keys / secrets (common key= patterns)
  • Bearer tokens

Replacements are placeholders like [EMAIL_REDACTED], [PHONE_REDACTED], etc. Use scrambled mode for compact IDs like [E_a7f3b2], [P_9c2e1d] that stay consistent across the file.


Installation

Via npm:

npm install -g pii-masker    # CLI globally: pii-mask
npm install pii-masker     # Or as a project dependency

From source (clone this repo):

git clone https://github.com/your-username/pii-masker.git
cd pii-masker

For Cursor hooks, use the path where pii-masker lives:

  • Global install: $(npm root -g)/pii-masker
  • Local install: ./node_modules/pii-masker
  • Cloned repo: your local path, e.g. /Users/you/Projects/pii-masker

1. Cursor (IDE)

Cursor’s hooks run before a prompt is sent or a file is read. This repo includes two hooks:

  • beforeSubmitPrompt – If the prompt (or attached context) contains PII, submission is blocked and the user is asked to remove or mask it.
  • beforeReadFile – PII in file contents is masked before being sent as context to the AI (when Cursor supports returning modified content).

Project-level (this repo only)

If your project is this repo (or you copied it into your repo), Cursor will use the hooks from .cursor/hooks.json when you open the project. Commands are run from the project root with node hooks/mask-pii-prompt.js and node hooks/mask-pii-read-file.js.

Global (all projects in Cursor)

To run the same hooks in every Cursor workspace, point Cursor at your pii-masker repo with absolute paths (no need to copy files). The scripts load ../src/pii-patterns.js from their own directory.

  1. Create or edit ~/.cursor/hooks.json and point to the pii-masker install path:
{
  "version": 1,
  "hooks": {
    "beforeSubmitPrompt": [
      { "command": "env PII_MASKER_ASK_ON_PII=1 PII_MASKER_SCRAMBLED=1 node /path/to/pii-masker/hooks/mask-pii-prompt.js", "timeout": 10 }
    ],
    "beforeReadFile": [
      { "command": "node /path/to/pii-masker/hooks/mask-pii-read-file.js", "timeout": 10 }
    ]
  }
}

Replace /path/to/pii-masker with:

  • npm global: $(npm root -g)/pii-masker
  • npm local: ./node_modules/pii-masker (use absolute path in production)
  • Cloned repo: e.g. /Users/you/Projects/pii-masker

Cursor runs the command from its own context, so absolute paths are more reliable than ~.

Note: beforeSubmitPrompt cannot substitute a masked prompt; Cursor shows a dialog or blocks. The user can approve to send anyway or edit and resend.

Default behavior (PII detected): Shows an Approve/Deny dialog. Approve = send anyway (unmasked). Deny = cancel. Does not block completely—user can choose to proceed.

Warn-only mode: Set PII_MASKER_WARN_ONLY=1 to allow the prompt through with a warning (no dialog).

Ask mode: Set PII_MASKER_ASK_ON_PII=1 to create masked copies of attached files when PII is detected. User still sees Approve/Deny; on Deny, masked files (e.g. testfile.pii-masked.md) are available to attach instead.

Strict block mode: Set PII_MASKER_BLOCK_ON_PII=1 to block completely when PII is detected (legacy behavior).

Masked files for attachments (ask mode)

In ask mode (PII_MASKER_ASK_ON_PII=1), when you [Deny] the dialog, the hook writes masked copies of attached files next to the originals (e.g. testfile.mdtestfile.pii-masked.md). Attach those instead and resend; the model will only see redacted content. Combine with PII_MASKER_USE_IDS=1 and PII_MASKER_MAPPING_FILE=1 for ID substitution and lookup.

ID substitution and mapping

  • PII_MASKER_USE_IDS=1 – Replace PII with [EMAIL_1], [PHONE_1], [SSN_1], etc., instead of [EMAIL_REDACTED]. Same value gets the same ID everywhere (e.g. in prompt + all attachments).
  • PII_MASKER_SCRAMBLED=1 – Replace PII with deterministic hex IDs like [E_a7f3b2], [P_9c2e1d], [K_4b8d12] instead of *_REDACTED. Same value → same code everywhere. Use --mapping in the CLI to write a lookup file.
  • PII_MASKER_MAPPING_FILE=1 – Write the ID → real value mapping to .cursor/pii-mapping.json in the project root so you can see what [EMAIL_1] referred to. Useful for ID mode in both beforeSubmitPrompt (attachments) and beforeReadFile (file content when the agent reads a file).

Example .cursor/pii-mapping.json:

{
  "mappings": {
    "conv-123": {
      "[EMAIL_1]": "[email protected]",
      "[PHONE_1]": "555-123-4567"
    }
  },
  "updated": "2025-03-08T12:00:00.000Z"
}

2. VS Code / Cursor (extension)

The extension masks PII automatically when you paste (default: on). You can also run commands to mask selection or clipboard.

Install: See vscode-extension/INSTALL.md for:

  • Marketplace – Install from the VS Code Extensions Marketplace (when published).
  • From .vsix – Install from a .vsix file (Extensions → … → Install from VSIX).
  • From source – Run with F5 for development.

Publish to the marketplace: See vscode-extension/PUBLISHING.md for packaging (vsce package), creating a publisher, and publishing with vsce publish.

Behavior after install

  • Automatic (default): When you paste text in an editor, PII in that text is replaced with placeholders (e.g. [EMAIL_REDACTED]) before insertion. Turn off in Settings: search PII Masker and uncheck Mask on paste.
  • Commands: “Mask PII in selection” (replace selection with masked text), “Mask PII in clipboard (paste masked)” (next paste will be masked).

3. CLI / pipeline

Use the masker in scripts or CI so any content you send to a chatbot (or log) is masked.

Requirements: Node.js (no extra npm install; the script uses the local src/pii-patterns.js).

From the pii-masker directory:

# Stdin → stdout
cat file.txt | node cli.js

# With verbose (report findings to stderr)
echo "Contact me at [email protected]" | node cli.js -v

# File in, stdout out
node cli.js --file input.txt

# File in, file out
node cli.js --file input.txt --out masked.txt

# Substitute with IDs and write mapping (for pipelines or manual lookup)
node cli.js --file input.txt --out masked.txt --ids --mapping pii-mapping.json

# Scrambled mode: [E_a7f3b2], [P_9c2e1d] etc. (same value → same code)
node cli.js --file input.txt --out masked.txt --scrambled

# Scrambled + mapping for lookup
node cli.js --file input.txt --out masked.txt --scrambled --mapping pii-mapping.json

You can call pii-mask if installed globally, or node /path/to/pii-masker/cli.js in your pipeline.


Tests and proof of concept

Run all tests:

npm test

This runs unit tests for PII patterns (tests/pii-patterns.test.js) and integration tests for the Cursor hooks (tests/hooks.test.js).

Run only unit or hook tests:

npm run test:unit
npm run test:hooks

Proof of concept (see masking on sample data):

npm run demo

Or node demo/proof-of-concept.js. This prints before/after for sample strings (emails, phones, API keys, allowlisted values, and ID substitution with mapping), plus a quick CLI check.


Layout

pii-masker/
├── README.md                 # This file
├── package.json
├── cli.js                    # CLI entry
├── src/
│   └── pii-patterns.js       # Shared PII detection and masking
├── tests/
│   ├── run.js                # Test runner (npm test)
│   ├── pii-patterns.test.js  # Unit tests for masking
│   └── hooks.test.js         # Hook integration tests
├── demo/
│   └── proof-of-concept.js   # Demo script (npm run demo)
├── hooks/
│   ├── mask-pii-prompt.js    # Cursor beforeSubmitPrompt
│   └── mask-pii-read-file.js # Cursor beforeReadFile
├── .cursor/
│   └── hooks.json            # Cursor project-level hooks
└── vscode-extension/
    ├── package.json
    ├── extension.js          # VS Code commands
    └── pii-patterns.js       # Bundled copy for VSIX

Customization

  • Patterns: Edit src/pii-patterns.js to add or change regexes and replacement strings. Sync or copy the same logic into vscode-extension/pii-patterns.js if you use the extension.
  • Allowlist: The same file defines an ALLOWLIST so values like *@example.com, 123-45-6789, and 127.0.0.1 are not masked. Adjust as needed.
  • Cursor env (hooks):
    • PII_MASKER_ASK_ON_PII=1 – when PII detected, create masked copies of attachments; user sees Approve/Deny.
    • PII_MASKER_BLOCK_ON_PII=1 – block completely when PII detected (legacy strict mode).
    • PII_MASKER_SCRAMBLED=1 – use [E_a7f3b2], [P_9c2e1d], etc., instead of *_REDACTED.
    • PII_MASKER_WARN_ONLY=1 – allow prompt through with warning (no dialog).
    • PII_MASKER_USE_IDS=1 – use [EMAIL_1], [PHONE_1], etc. (for mapping file).
    • PII_MASKER_MAPPING_FILE=1 – write ID → value mapping to .cursor/pii-mapping.json.
  • Cursor: Use failClosed: true in hooks.json if you want hook failures (e.g. script not found) to block the action instead of allowing it.

Limitations

  • Client-side only: This does not protect you if you intentionally send PII or use another client. For organization-wide policy, consider server-side or proxy masking.
  • Cursor: Prompt substitution is not supported yet (block or warn-only only). File-content masking in beforeReadFile may not be applied by Cursor in all cases.
  • Detection: Regex-based; false positives and false negatives are possible. Allowlisting and warn-only mode help reduce friction.

See DESIGN.md for a fuller discussion of tradeoffs and alternatives.


Publishing to npm

  1. Replace your-username in package.json with your GitHub username (or remove repository / homepage if not using GitHub).
  2. Log in: npm login
  3. Publish: npm publish (for scoped packages: npm publish --access public)

License

MIT.