n8n's Guardrails node masks your PII. It doesn't give it back. Here's why that matters. N8n's Guardrails node masks PII but discards the original values, making it impossible to restore them downstream. A developer built Privent to solve this by tokenizing PII before LLM processing and detokenizing it afterward, preserving the mapping without exposing sensitive data to the LLM. 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. Here's a workflow almost everyone building support automation eventually writes: Webhook: support ticket → Guardrails: Sanitize Text → LLM: summarize → write summary to CRM 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." 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. 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. This is the exact gap we built Privent https://www.privent.ai 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 The ticket becomes: "Hi, I'm NAME 001 , my account email is EMAIL 002 , and I was charged twice for my subscription." 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." That's the whole difference. Mask going in, restore coming out, and the LLM is never in the loop for either direction. 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 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. 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. cd ~/.n8n npm install n8n-nodes-privent Tokenless mode, no signup: github.com/privent-ai/n8n-nodes-privent https://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.