DEV Community

Asil Ozyildirim
Asil Ozyildirim

Posted on

n8n's Guardrails node masks your PII. It doesn't give it back. Here's why that matters.

n8n shipped a native Guardrails node back in November. PII detection, jailbreak protection, content filtering — all built into the platform, zero external services. It's a genuinely good default, and if you're building AI workflows in n8n and not using it yet, you should be.

But we kept hitting the same wall with it, and once you see the wall, you can't unsee it.

The wall

Here's a workflow almost everyone building support automation eventually writes:

[Webhook: support ticket] → [Guardrails: Sanitize Text] → [LLM: summarize]
                                                          → [write summary to CRM]
Enter fullscreen mode Exit fullscreen mode

A ticket comes in: "Hi, I'm Sarah Chen, my account email is sarah.chen@acme.com, and I was charged twice for my subscription."

Guardrails' Sanitize Text mode catches the PII before it hits the LLM:

"Hi, I'm [NAME], my account email is [EMAIL], and I was charged twice for my subscription."
Enter fullscreen mode Exit fullscreen mode

Good. The LLM never sees Sarah's real email. It summarizes: "[NAME] reports a duplicate subscription charge tied to [EMAIL]."

Now write that to the CRM.

And here's the wall: you can't. [NAME] and [EMAIL] are gone. Not encrypted, not hashed — gone. Guardrails redacts, and redaction is a one-way door. There's no way to ask "what was [EMAIL] actually?" because the node never kept a record. It just deleted the substring and moved on.

So now you're stuck writing "[NAME] reports a duplicate charge tied to [EMAIL]" into a customer record that's supposed to say Sarah Chen. You either accept a useless CRM entry, or you bypass Guardrails for this step and send the raw ticket to the LLM anyway — which defeats the entire point of having a guardrail in the first place.

Why this isn't a Guardrails bug

I want to be fair to n8n here, because this isn't a flaw in their implementation — it's the design goal. Guardrails is a content moderation primitive. Its job is: does this text violate a policy, and if so, neutralize it. Jailbreak detection, NSFW filtering, keyword blocking — for all of those, throwing the violating content away is exactly correct. You don't want the jailbreak attempt preserved anywhere.

PII just happens to share a node with those other checks, and inherits the same throw-it-away behavior. That's fine for compliance scanning ("did this text contain a credit card number, yes/no"). It's not fine the moment your workflow needs the value of that PII downstream — which, if you're doing anything beyond pure logging, is most real workflows.

The piece that was missing: reversibility

This is the exact gap we built Privent to close. Same idea as Guardrails' sanitize mode — mask sensitive values before they reach an LLM — but with one architectural difference: the mapping between a token and its original value is kept, not destroyed.

[Webhook] → [Privent: Tokenize] → [LLM: summarize] → [Privent: Detokenize] → [write to CRM]
Enter fullscreen mode Exit fullscreen mode

The ticket becomes:

"Hi, I'm [NAME_001], my account email is [EMAIL_002], and I was charged twice for my subscription."
Enter fullscreen mode Exit fullscreen mode

The LLM summarizes using the tokens, same as before — it still never sees Sarah Chen or her real email. But at the trusted egress point (right before you write to the CRM), Detokenize swaps the tokens back:

"Sarah Chen reports a duplicate subscription charge tied to sarah.chen@acme.com."
Enter fullscreen mode Exit fullscreen mode

That's the whole difference. Mask going in, restore coming out, and the LLM is never in the loop for either direction.

"Isn't that just... storing the PII somewhere else?"

Fair question, and worth answering directly instead of hand-waving it. Yes — somewhere, a token has to map back to a real value, or detokenization is impossible by definition. The question that actually matters is where that mapping lives and who can reach it.

We built two modes specifically because the answer to that question depends on your workflow:

Tokenless mode — no API key, no account. The token↔value map lives in n8n's own workflow static data, scoped to a single execution's sessionId. Nothing leaves your n8n instance. This is the mode for "I just need tokenize→LLM→detokenize inside one workflow," which covers the support-ticket example above completely.

npm install n8n-nodes-privent
# set Authentication = Tokenless (Visitor) on the node, done
Enter fullscreen mode Exit fullscreen mode

Cloud mode — for when you need the mapping to survive across multiple workflow runs, or across different workflows entirely (multi-agent handoffs, async processes where tokenize happens in one execution and detokenize happens in another, hours later). That needs a real persisted vault, which means a backend, which means an API key.

If your workflow is "one webhook in, one response out," you don't need Cloud mode. Tokenless mode covers it, and the mapping never crosses your network boundary.

Where Guardrails is still the right tool

I don't want to oversell this. If your use case is purely "block this if it contains a jailbreak attempt" or "don't let credit card numbers reach this LLM, full stop" — Guardrails is simpler, it's zero-install, and you should use it. We're not trying to replace it.

The line is pretty clean once you draw it out:

Need Use
Block/flag content that violates a policy Guardrails
Mask PII and never need it again Guardrails (Sanitize mode)
Mask PII, then restore the real value downstream Privent
Jailbreak / prompt injection detection Guardrails
Audit trail of which agent touched which token Privent (Cloud mode)

A lot of workflows genuinely only need the left column. Some — anything that writes an LLM-processed result back into a system of record with the subject's real identity — need the right one, and that's the gap nobody else in the n8n ecosystem is covering yet.

Try it

cd ~/.n8n
npm install n8n-nodes-privent
Enter fullscreen mode Exit fullscreen mode

Tokenless mode, no signup: github.com/privent-ai/n8n-nodes-privent

If you've hit this same wall with Guardrails — or solved it some other way — I'd genuinely like to hear how. Drop it in the comments.

Top comments (2)

Collapse
 
marrouchi profile image
Med Marrouchi

Really nice feature! I think safeguard routines should be customizable and extendable.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.