Skip to main content
Glama
fairquery

fairquery-llm-data-guard

Official

LLM Data Guard: PII & Secret Redactor

Fairquery Apify Actor that finds and redacts personal data (PII) and secrets in text, HTML and PDF documents before they are sent to an LLM, a vector store or a third-party API. Each document gets a risk level, a list of findings (type, offsets, masked preview) and, in redact mode, a clean output_text you can pass straight to your model. Placeholders are reversible, so you can put the original values back into the model's answer.

No data retention. The Actor never logs document content and writes nothing except the result rows in the run's default dataset and a counts-only RUN_SUMMARY. By default it also deletes the run's INPUT record when it finishes (purgeInputAfterRun). Raw values are not stored in findings unless you turn on includeFindingValues. You control the dataset; delete it (or the run) once you have read it.

When to use this Actor (LLM / tool selection)

Use it when an agent or pipeline needs to:

  • Strip emails, phone numbers, SSNs, card numbers, IBANs and IP addresses from prompts, chat logs, support tickets or CRM notes before LLM calls

  • Catch leaked credentials (AWS, GitHub, Slack, Stripe, OpenAI, Anthropic, Google, private keys, JWTs, password=...) in logs, code snippets and config files

  • Pseudonymise a dataset for RAG / fine-tuning with consistent placeholders ([EMAIL_1], [PERSON_2])

  • Restore real values in the LLM's answer (mode: "restore")

  • Audit a batch of documents for sensitive-data risk (mode: "detect")

Covers OWASP LLM Top 10 risk LLM02 Sensitive Information Disclosure at the input side. It is a pattern-and-validation engine, not a guarantee: always keep defense in depth.

Related MCP server: classifinder-mcp

What it detects

Category

Types

Validation

PII

EMAIL, PHONE, SSN, CREDIT_CARD, IBAN, UK_NINO, IP_ADDRESS

Luhn + issuer prefix for cards, mod-97 + country length for IBANs, libphonenumber for phones, SSN area/group rules

PII (opt-in)

PERSON, LOCATION, STREET_ADDRESS

Open-source NER (compromise, English) and street-address patterns

Secrets

PRIVATE_KEY, AWS_ACCESS_KEY, AWS_SECRET_KEY, GITHUB_TOKEN, GITLAB_TOKEN, SLACK_TOKEN, SLACK_WEBHOOK, STRIPE_KEY, GOOGLE_API_KEY, OPENAI_KEY, ANTHROPIC_KEY, HUGGINGFACE_TOKEN, NPM_TOKEN, SENDGRID_KEY, TWILIO_KEY, AZURE_STORAGE_KEY, JWT, URL_CREDENTIALS

Gitleaks-style rules

Secrets

GENERIC_SECRET (api_key=…, token: …, password=…)

Shannon-entropy threshold (minEntropy), placeholder words ignored

Secrets (opt-in)

HIGH_ENTROPY_STRING

Any 20+ char random-looking token

Overlapping matches are resolved (secrets > cards/IBAN > SSN > email > IP > phone > address > names), so a card number is never also reported as a phone.

Redaction styles

redactionStyle

Example

Reversible

placeholder (default)

Mail [EMAIL_1] or call [PHONE_1]

Yes, with returnPlaceholderMap and mode: "restore"

mask

j***@a***.com, **** **** **** 1111, AKIA****************

No

hash

[EMAIL:3f2a9c0d1b7e] (salted SHA-256 prefix)

No; stable across runs if you set hashSalt

Input

Field

Type

Default

Description

texts

string[]

example

One document per entry

documents

{id,text}[]

[]

Documents with your own IDs

documentUrls

string[]

[]

Public txt/md/json/csv/HTML/PDF URLs (max 10 MB each)

mode

detect | redact | restore

redact

redactionStyle

placeholder | mask | hash

placeholder

returnPlaceholderMap

bool

false

Adds placeholder_map per row (contains originals!)

consistentPlaceholders

bool

true

Same value → same placeholder across documents

placeholderMap

object

{}

For restore mode

hashSalt

secret string

random per run

For hash style

detectPii / detectSecrets

bool

true

detectNames / detectAddresses / entropyScan

bool

false

Opt-in detectors

minEntropy

number

3.5

Bits/char for generic secrets

defaultPhoneRegion

string

US

For numbers without + prefix

entityTypes

string[]

all

Only report these types

allowList

string[]

[]

Values never flagged

includeFindingValues

bool

false

Put raw values into findings

maxDocuments / maxCharsPerDocument

int

1000 / 1,000,000

Safety caps

purgeInputAfterRun

bool

true

Delete the INPUT record at the end

{
  "texts": ["Hi, I'm Jane (jane.doe@acme.com, +1 415-555-0132). Card 4111 1111 1111 1111.", "AWS key AKIAIOSFODNN7EXAMPLE"],
  "mode": "redact",
  "redactionStyle": "placeholder",
  "returnPlaceholderMap": true
}

Output

One row per document (type: "document") plus machine-readable type: "error" rows.

{
  "schema_version": "1.0.0", "type": "document", "id": "text-1", "source": "text", "chars": 78, "mode": "redact",
  "finding_count": 3, "risk_level": "high",
  "counts_by_type": { "EMAIL": 1, "PHONE": 1, "CREDIT_CARD": 1 },
  "findings": [
    { "type": "EMAIL", "category": "pii", "rule": "email", "confidence": "high", "start": 14, "end": 31, "length": 17, "preview": "j***@a***.com", "replacement": "[EMAIL_1]" }
  ],
  "output_text": "Hi, I'm Jane ([EMAIL_1], [PHONE_1]). Card [CREDIT_CARD_1].",
  "placeholder_map": { "[EMAIL_1]": "jane.doe@acme.com", "[PHONE_1]": "+1 415-555-0132", "[CREDIT_CARD_1]": "4111 1111 1111 1111" }
}

risk_level: high = any secret or card/SSN/IBAN/NI number; medium = other confident PII; low = only low-confidence (NER/entropy) hits; none.

Restore after the LLM answers:

{ "mode": "restore", "texts": ["Dear [EMAIL_1], your card ending [CREDIT_CARD_1]…"], "placeholderMap": { "[EMAIL_1]": "jane.doe@acme.com" } }

Error codes: INPUT_EMPTY, MAX_DOCUMENTS_EXCEEDED, PLACEHOLDER_MAP_MISSING, DOCUMENT_FETCH_FAILED (error rows are never charged).

RUN_SUMMARY (key-value store) holds counts per type, charged events and settings only, never text.

Pricing

Pay per event:

Event

When

document-processed

Each document scanned (or restored)

finding

Each PII/secret finding reported

Error rows are never charged. See the pricing tab for current prices.

Memory / runtime

Default 256 MB, no browser, no proxy. Regex detectors process roughly 1–5 MB of text per second; NER (detectNames) is slower, so give it 512 MB for big batches. PDFs are parsed with unpdf (text layer only, no OCR).

MCP / Apify tools

Call from agents via Apify MCP with Actor fairquery/llm-data-guard-pii-secrets:

{ "actor": "fairquery/llm-data-guard-pii-secrets", "input": { "texts": ["..."], "mode": "redact" } }

Local stdio MCP server

The mcp/ folder is a stdio MCP server (TypeScript, @modelcontextprotocol/sdk) with two tools, both with annotations and output schemas:

Tool

What it does

Cost

guard_text

Runs this Actor and returns the dataset rows

Needs APIFY_TOKEN, billed per event

list_detectors

Lists detectable types, redaction styles and events

Free, local, no token

cd mcp && npm install && npm run build
node scripts/smoke-test.mjs                          # initialize + tools/list + free tool, no token
APIFY_TOKEN=... node scripts/smoke-test.mjs --call   # real call
{ "mcpServers": { "fairquery-llm-data-guard": { "command": "node", "args": ["/path/to/llm-data-guard-pii-secrets/mcp/dist/index.js"], "env": { "APIFY_TOKEN": "<your Apify token>" } } } }

Docker: the root Dockerfile builds the MCP server image (docker build -t fairquery-llm-data-guard-mcp .); it is also the Dockerfile for Glama. The Actor image is .actor/Dockerfile. glama.json lists fairquery as maintainer.

Local development

npm install
npx apify run      # input from storage/key_value_stores/default/INPUT.json
npm test

Kits & templates

Optional guides from Fairquery for wiring this Actor into agents and automations (the Actor works fine without them):

Disclaimer

Pattern-based detection finds most but not all sensitive data: unusual formats, non-English names, images and scanned PDFs (no OCR) can slip through, and some matches are false positives. Use it as one layer of a data-protection program, not as a compliance certification. Only process data you are allowed to process.

  • License: MIT

Available Tools

2 tools
guard_textDetect / redact PII and secrets before LLM useA
Read-onlyIdempotent

WHAT: Scan text documents (or public document URLs: txt/md/json/csv/HTML/PDF) for PII (emails, phones, US SSNs, Luhn-valid cards, IBANs, UK NINOs, IPs, optional person names/addresses) and secrets (AWS/GitHub/Slack/Stripe/OpenAI/... keys, JWTs, private keys, URL credentials, high-entropy key=value). mode="redact" returns sanitized text; mode="restore" puts originals back into LLM output using a placeholder map. WHEN TO USE: before sending prompts, tickets, logs or files to an LLM or third party; to audit text for leaked credentials; to de-anonymize an LLM answer after a placeholder redaction. WHEN NOT TO USE: to see which entity types exist or pick entityTypes, call list_detectors (free, local). Not for binary files/images (PDF text layer only, no OCR) or for validating whether an email is deliverable. COST: paid. Runs Apify Actor fairquery/llm-data-guard-pii-secrets with your APIFY_TOKEN; pay-per-event billed per document processed and per finding (error rows free). Typical run a few seconds. RETURNS: {count, items}. One type="document" row per input with id, source, chars, truncated, mode, finding_count, counts_by_type, risk_level, findings[] (type, offsets, masked preview; raw values are not returned), output_text (redact/restore modes), placeholder_map (only if returnPlaceholderMap=true); or type="error" rows with code/message. EXAMPLE: {"texts":["Mail jane@acme.com, key AKIAIOSFODNN7EXAMPLE"],"mode":"redact","redactionStyle":"placeholder"} -> output_text with the email replaced by [EMAIL_1] and the key by a placeholder; findings lists EMAIL and AWS_ACCESS_KEY. Provide texts and/or documentUrls (at least one).

ParametersJSON Schema
NameRequiredDescriptionDefault
modeNo"detect" = report findings only; "redact" (default) = also return output_text with values replaced; "restore" = replace placeholders in texts with originals from placeholderMap.
textsNoDocuments to scan, one string per document (prompt, chat message, ticket, log line, file content). Example: ["Hi, I am Jane (jane.doe@acme.com)"]. Optional if documentUrls is given.
allowListNoExact values that are never flagged, e.g. ["support@yourcompany.com"]. Default [].
detectNamesNoDefault false. Detect person names with English NER (lower precision, slightly slower).
entityTypesNoOnly report these entity types, e.g. ["EMAIL","CREDIT_CARD","AWS_ACCESS_KEY"]. Omit/empty = all enabled detectors. Valid names: see list_detectors.
entropyScanNoDefault false. Also flag unlabeled random-looking tokens of 20+ chars (catches unknown key formats; may flag hashes/IDs).
documentUrlsNoPublic http(s) URLs of txt, md, json, csv, HTML or PDF files (max 10 MB each; PDFs text layer only). Example: ["https://example.com/report.pdf"]. Optional if texts is given.
placeholderMapNoOnly for mode="restore": map of placeholder -> original value returned by a previous redact call, e.g. {"[EMAIL_1]":"jane@acme.com"}. Default {}.
redactionStyleNoUsed in redact mode. "placeholder" (default) = [EMAIL_1], reversible via placeholder map; "mask" = j***@a***.com / **** 1111; "hash" = [EMAIL:3f2a9c0d1b7e] salted sha256 prefix.
detectAddressesNoDefault false. Detect street addresses (English formats) and NER place names.
defaultPhoneRegionNoISO 3166-1 alpha-2 country code used to parse phone numbers written without +country prefix, e.g. "US" (default), "DE", "GB".
returnPlaceholderMapNoDefault false. If true, each row includes placeholder_map {"[EMAIL_1]":"jane@acme.com"} needed for restore mode. Contains the original sensitive values.

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYesNumber of rows in items
itemsYesDataset rows: type=document (findings, risk_level, output_text) or type=error

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: discloses the paid/pay-per-event cost model, the backing Actor and required APIFY_TOKEN, that raw sensitive values are not returned, that PDFs are text-layer only (no OCR), and the exact {count, items} shape including error rows. Annotations already cover safety, and the description adds rich operational context on top.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with labeled WHAT / WHEN TO USE / WHEN NOT TO USE / COST / RETURNS / EXAMPLE sections. Despite its length, every section earns its place given 12 parameters, a paid external Actor, and three operating modes.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers the at-least-one-of constraint (texts and/or documentUrls), unsupported inputs, cost, auth, and return shape even though an output schema exists. For a complex multi-mode tool with an external dependency, nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description earns extra by explaining mode semantics, illustrating redactionStyle output, and pointing entityTypes validation at list_detectors. It adds meaningful interpretation (e.g. returnPlaceholderMap contains original sensitive values) rather than restating the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States specific verbs (scan, redact, restore) and resources (text documents, public document URLs) and enumerates exactly what is detected (PII types, secrets). It distinguishes its three modes and names the sibling list_detectors, so an agent can separate it from alternatives without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit WHEN TO USE (before sending prompts/tickets/logs to an LLM, auditing for leaked credentials, de-anonymizing output) and WHEN NOT TO USE (entity discovery → list_detectors; no binary/image support; not email-deliverability validation). Both conditions and the alternative tool are named, leaving nothing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_detectorsList detectors and redaction styles (free)A
Read-onlyIdempotent

WHAT: Static catalog of the PII and secret entity types guard_text can detect, the available redaction styles, and the billable pricing events. WHEN TO USE: before guard_text, to choose entityTypes / redactionStyle or to explain coverage to a user. WHEN NOT TO USE: to actually scan or redact text - use guard_text. COST: free; local, no network, no APIFY_TOKEN, deterministic. RETURNS: {pii: string[], secret: string[], redaction_styles: {style: example}, pricing_events: {event: unit}}. Takes no arguments. EXAMPLE: {} -> {"pii":["EMAIL","PHONE",...],"secret":["AWS_ACCESS_KEY",...],...}

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
piiYesPII entity types (opt-in ones marked)
secretYesSecret/credential entity types
pricing_eventsYesBillable Apify event -> unit
redaction_stylesYesRedaction style -> example output

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, but the description adds value beyond them: cost (free), no network, no APIFY_TOKEN required, and deterministic output. It stops short of 5 only because return shape is largely restated from the existing output schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Header-prefixed sections (WHAT/WHEN/COST/RETURNS/EXAMPLE) are scannable and front-loaded, with the routing rule stated in the first two blocks. Every sentence carries information; nothing is padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a free, argument-less catalog tool the definition covers purpose, routing, cost/auth requirements, return shape and an example. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Zero parameters, so the baseline is 4 per the rubric. The description reinforces this by stating 'Takes no arguments' with an empty-object example, leaving no ambiguity for the caller.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (catalog of PII/secret entity types, redaction styles, pricing events) and explicitly scopes it as the static catalog that guard_text relies on. An agent can distinguish it from guard_text without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit WHEN TO USE (before guard_text, to choose entityTypes/redactionStyle) and WHEN NOT TO USE (to actually scan or redact — use guard_text), naming the sibling as the alternative. Routing is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv0.1.0
    • First observedguard_text
    • First observedlist_detectors

TDQS

A4.7/5.0

Scored across 2 tools

Disambiguation5/5

guard_text (scan/redact/restore text) and list_detectors (static catalog lookup) have clearly distinct purposes, and the descriptions explicitly cross-reference each other with WHEN NOT TO USE guidance. An agent can unambiguously pick the right tool, including the ordering hint to call list_detectors first.

Naming Consistency5/5

Both names use the same snake_case verb_noun convention (guard_text, list_detectors) with an imperative verb leading. No casing or style mixing across the set.

Tool Count4/5

Two tools is on the thin side, but the server wraps a single focused actor: one multi-mode tool covers scan/redact/restore and one free local helper exposes the entity catalog. Nothing feels redundant, though the surface is minimal.

Completeness4/5

Core lifecycle (discover entity types, scan, redact, restore) is fully covered, with inputs for raw text and document URLs. Gaps are minor and mostly out-of-scope by design (no OCR/images, no async job polling for long Apify runs, no custom entity patterns).

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

  • Detect and redact PII and secrets before text reaches an LLM, with reversible placeholders.

  • Detects and redacts PII (emails, phones, SSNs, names, addresses) from text. $0.02/call via x402.

  • Redact personal data from text before your agent sends it to a model or stores it: names, contact details, ID numbers, financial and health identifiers, card numbers, plus any exact terms you add. Nothing stored, no third-party AI. Tools - redact_text: returns the redacted text and a count of what was removed, by type. Never the removed values. Options: restrict to particular data types, add exact terms to remove, choose the replacement style (a type label such as <PERSON> by default) and set a confidence threshold. - list_entity_types: lists the detectable data types. Free. Data handling - Nothing you send is stored. Text is processed in memory and discarded when the call returns. - No third-party AI. Text is never sent to OpenAI, Anthropic, Google or any other outside model. - Tool arguments are never logged. Only counts are kept: credits used, a timestamp and how many of each type were found. PDFs, including scanned pages, are handled by the REST API with the same key and credits. They aren't offered as an MCP tool because a file doesn't fit in a tool call. Pricing: 1 credit per call plus 1 per 1,000 characters. 10 free credits on sign-up, no card. Credit packs from $5; purchased credits never expire. Failed calls and repeated identical calls are free. Setup and API key: https://eleyed.com/mcp?utm_source=glama&utm_medium=directory&utm_campaign=listing

  • Check a document for hidden text before your agent reads it. PDF, Office, RTF, HTML.

Related MCP Servers