Docs / Architecture & integration

Mask PII locally before it reaches any LLM

TrustNode is a local-first DevSecOps toolkit: @trustnode/core masks PII with deterministic tokens in your app, backend, CLI, or Chrome extension before text reaches LLM APIs. The TrustNode API syncs policy and quota — it does not receive raw prompts to mask. Masking always runs in your app, backend, CLI, or browser extension via @trustnode/core. The TrustNode API manages policy, quotas, and usage — it does not receive raw prompts to mask.

On this page

How TrustNode works

TrustNode is an egress firewall for AI: customer or employee text is tokenized before it leaves your environment toward ChatGPT, Claude, Gemini, or your own model providers.

  1. 1. Policy sync — Your app or extension calls GET /v1/config with a publishable key to learn which detectors and Brand Guard terms are enabled.
  2. 2. Local mask — Before any outbound LLM call, run maskPii() in-process (Node backend, edge worker, browser extension inject script, etc.).
  3. 3. Safe egress — Only tokens like [EMAIL_1] reach the model provider.
  4. 4. Telemetry — Report masked_count via POST /v1/telemetry so workspace quota stays accurate.
Mobile / Web / Server app          Chrome (employees)
        │                                    │
        ▼                                    ▼
 Your backend ── maskPii(@trustnode/core)    Extension inject ── same core engine
        │                                    │
        ├─► OpenAI / Claude / Gemini         ├─► chatgpt.com / claude.ai / …
        │                                    │
        └─► TrustNode API (config + quota)   └─► TrustNode API (config + quota)

What it detects

High-precision detectors (regex + validators such as Luhn / IBAN / TC kimlik). Designed to avoid shredding normal prose.

KindExamples
emailuser@company.com
creditCard4111… (Luhn)
ibanTR… / DE…
phone+90…, US, national
tr-tckn11-digit Turkish ID
nationalIdUS SSN, UK NINO, ES DNI, …
passport / taxIdPassport & tax ID patterns
ipAddress / macAddressIPv4/IPv6, MAC
Brand GuardCompetitors & custom terms

SDK integration (web, mobile, backend)

For product AI assistants — whether the UI is a mobile app, web app, or internal tool — run masking on your server (or a trusted BFF) with @trustnode/core. Do not put API keys in mobile binaries.

bash
# Private beta: @trustnode/core is not on the public npm registry yet.
# After waitlist access we share a tarball / private registry invite, or you
# link the package from the TrustNode monorepo:
#
#   npm install ../path/to/packages/trustnode-core-sdk
#   # or in package.json: "@trustnode/core": "file:../trustnode-core-sdk"
javascript
import { maskPii, unmaskPii } from '@trustnode/core';

// Run in YOUR process (backend, BFF, or edge) — not as a remote "mask this text" API call.
const vault = new Map();

async function handleUserMessage(userText) {
  const { output: masked, matches } = maskPii(userText, {
    vault,
    kinds: ['email', 'creditCard', 'phone', 'iban', 'tr-tckn', 'nationalId'],
  });

  // Only the masked prompt ever reaches the external LLM.
  const llmReply = await callYourLlm(masked);

  // Restore originals before showing the user (optional).
  return { reply: unmaskPii(llmReply, vault), entitiesMasked: matches.length };
}

Backend proxy pattern (recommended)

javascript
// Recommended for mobile + web apps:
// Mobile/Web client → your backend → maskPii(@trustnode/core) → OpenAI / Claude / Gemini
//
// Auth: use the same publishable key (tn_pub_…) as Browser Shield for config + telemetry.
// tn_secret_… is optional on paid plans for server-only clients — never ship it to browsers/mobile.
//
// 1) Fetch workspace policy (cache briefly; respect quotaExceeded)
const config = await fetch('https://api.trustnodehq.com/v1/config', {
  headers: { Authorization: `Bearer ${process.env.TRUSTNODE_PUBLISHABLE_KEY}` },
}).then((r) => r.json());

// 2) Mask locally with the same engine the Chrome extension uses
const { output, matches } = maskPii(req.body.prompt, {
  kinds: Object.entries(config.default_rules ?? {})
    .filter(([, enabled]) => enabled)
    .map(([kind]) => kind),
  brandGuard: { customTerms: config.brand_guard_terms ?? [] },
});

// 3) Call the LLM with masked text only
// 4) Report usage so dashboard Home / Billing quota stays accurate
await fetch('https://api.trustnodehq.com/v1/telemetry', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.TRUSTNODE_PUBLISHABLE_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    masked_count: matches.length,
    events: [{ at: Date.now(), platform: 'my-app', masked_count: matches.length }],
  }),
});

API Gateway reference

Base URL: https://api.trustnodehq.com (live control plane). Create keys in the dashboard → API Keys. Use a publishable tn_pub_… key for Browser Shield and for backend /v1/config + /v1/telemetry. Optional tn_secret_… keys are for trusted servers on Startup+ plans — never ship them to browsers or mobile apps. Revoking a key does not reset workspace quota or audit history.

EndpointPurpose
GET /v1/configPolicy (default_rules), Brand Guard terms, tier, quota snapshot
POST /v1/telemetryReport masked_count / entities_masked; deducts monthly quota (rate-limited)
GET /healthLiveness check

Fetch policy:

bash
curl -s https://api.trustnodehq.com/v1/config \
  -H "Authorization: Bearer tn_pub_YOUR_KEY"

Report usage:

bash
curl -s -X POST https://api.trustnodehq.com/v1/telemetry \
  -H "Authorization: Bearer tn_pub_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"masked_count": 3}'

Browser Shield (Chrome extension)

For employees using ChatGPT, Claude, Gemini, and similar sites in Chrome, TrustNode Shield runs the same core engine in the page (main-world inject). Masking happens on the device before the browser POST leaves. The extension does not use your dashboard login session — it authenticates with a tn_pub_… publishable key and only calls the TrustNode API for policy + usage telemetry.

  1. Sign up / sign in at app.trustnodehq.com
  2. Open API Keys → generate a publishable key (tn_pub_…). Copy it immediately — it is shown once.
  3. Install TrustNode Shield (Chrome), open the popup, paste the key, click Save.
  4. Wait for Connected. Without a key, masking stays off.
  5. Use ChatGPT / Claude as usual — PII is replaced with tokens like [EMAIL_1] before the request leaves the browser. Usage appears on the dashboard Home gateway counter.

Embedding TrustNode in your own product? Same local engine + API Gateway pattern — see API Gateway and SDK integration.

CLI scan (PLG)

Freemium local repo scan finds exposed PII, shows blurred teasers in the terminal, and opens a magic-link risk report. Detection still runs locally via @trustnode/core.

bash
# Private beta: @trustnode/cli is not on the public npm registry yet.
# From the TrustNode monorepo (after npm install in packages/trustnode-core-sdk):
cd apps/trustnode-cli
npm install
export TRUSTNODE_API_URL=https://api.trustnodehq.com
export TRUSTNODE_DASHBOARD_URL=https://app.trustnodehq.com
npm run scan -- .

Brand Guard

Redact custom dictionary terms locally before egress — no extra LLM classification step. Workspace terms from the dashboard arrive as brand_guard_terms on GET /v1/config.

javascript
import { maskPii } from '@trustnode/core';

// Dashboard Policies → Brand Guard terms sync via GET /v1/config as brand_guard_terms.
// Pass them as customTerms (flat deny-list). Advanced competitor splits are SDK-only for now.
const { output } = maskPii("Share the Project Nightingale deck with finance.", {
  brandGuard: {
    customTerms: ['Project Nightingale'], // e.g. config.brand_guard_terms
  },
});
// Matched terms are redacted locally — never vaulted.

Tokenization & Vault

Replace PII with stable tokens for the model, then restore originals for the end user with the same vault map.

javascript
import { maskPii, unmaskPii } from '@trustnode/core';

const vault = new Map();
const userInput = "Contact jane@example.com about the new project.";
const masked = maskPii(userInput, { vault });
// masked.output -> "Contact [EMAIL_1] about the new project."

const llmResponse = `I drafted a note for ${masked.output}`;
const finalOutput = unmaskPii(llmResponse, vault);
// Restores [EMAIL_1] → jane@example.com for the end user only.

Next steps

FAQ

Architecture and integration questions.

Does the TrustNode API mask my text in the cloud?
No. Masking always runs locally with @trustnode/core inside your backend, app, CLI, or Chrome extension. The API (GET /v1/config, POST /v1/telemetry) syncs policies and usage quotas only — raw prompts are not uploaded to TrustNode for masking.
How do I protect a mobile or web AI assistant?
Send user messages to your own backend first. Call maskPii() there with @trustnode/core, then forward only the masked text to OpenAI, Claude, or Gemini. Sync policy via GET /v1/config and report usage with POST /v1/telemetry using a publishable tn_pub_ key. Never put API keys in the mobile/web binary.
How does the Chrome extension relate to the API?
Browser Shield uses the same core engine in the page to mask ChatGPT, Claude, and similar sites before the browser request leaves the device. It calls the TrustNode API only for workspace config and telemetry — not to mask chat content remotely. Paste a tn_pub_ key from Dashboard → API Keys.
Can I install @trustnode/core from npm today?
Not from the public npm registry yet — TrustNode is in private beta. After waitlist access we share a tarball or private registry invite; evaluators can also link the package from the TrustNode monorepo. The live API gateway at api.trustnodehq.com already serves config and telemetry.
Does revoking an API key reset my quota?
No. Usage and monthly quota live on the workspace, not on the key. Revoke + create a new tn_pub_ key only rotates credentials; Home usage and audit history stay intact.
What is TrustNode?
TrustNode is a local-first DevSecOps toolkit: @trustnode/core masks PII with deterministic tokens in your app, backend, CLI, or Chrome extension before text reaches LLM APIs. The TrustNode API syncs policy and quota — it does not receive raw prompts to mask.
What is deterministic tokenization?
The same input value consistently maps to the same token (for example [CREDIT_CARD_1]) within a vault session, so debugging and support stay possible without sending raw PII to the model.