You have projects with dozens of files: markdown articles, JSON workflow exports, Python scripts, config files. Any one of them can accidentally contain:
The problem isn't that these leaks happen — it's that you won't know until someone finds them. A leaked credential in a public repo or dashboard can cost $5,000 to $50,000+ in damages, depending on the exposure.
Manual audits don't work. You forget. You get busy. And the one time you skip it is the one time something slips through.
This workflow gives you a fully automated privacy scanner that runs weekly, alerts you immediately if anything changes, and costs exactly $0.
| Tool | What It Does | Cost |
| bash + grep | Pattern matching for emails, phones, keys, IPs | Free |
| Python 3 | JSON parsing for credential references in n8n workflows | Free |
| cron | Weekly automated schedule (Sundays at 3am) | Free |
| n8n (self-hosted) | Webhook-triggered on-demand scans + email alerts | Free |
| systemd | Keeps the webhook server running | Free |
Total cost: $0 — all tools are built-in or free.
Before building the scanner, here are the categories of private data to detect:
| Category | What It Catches | Example |
| 📧 Non-Project Emails | External email addresses in files | `service@client.com` in a workflow JSON |
| 📞 Phone Numbers | US/International phone formats | `555-123-4567` in a config file |
| 🔑 API Keys / Tokens | Known key formats (sk-, AKIA, ghp_, xox-) | `sk-proj-abc123...` in a script |
| 🆔 n8n Credential IDs | Credential references in JSON exports | `credential ID "2"` in a workflow file |
| 🔐 Passwords / Secrets | `password=`, `secret=`, `token=` assignments | `password=supersecret123` in a .env |
| 🌐 Embedded URL Creds | URLs containing `user:pass@` | `https://admin:pass@api.example.com` |
| 🏢 Company / Client Names | `client:`, `company:` fields with real names | `company: ALSEC` in a dashboard |
| 🌍 Public IP Addresses | Non-private IPs in infrastructure docs | Server IPs, API endpoint IPs |
Each category gets its own scan function, making the system modular and easy to extend.
Create a single bash script called `check-privacy.sh` that runs all scans and generates a markdown report.
Each scan uses `find` + `grep` with smart exclusions:
# Scan for emails (excludes project-owned domains and placeholders)
check_emails() {
find "$TARGET" -type f \( -name '*.md' -o -name '*.json' -o -name '*.py' ... \) \
! -path '*/node_modules/*' ! -path '*/.git/*' \
-exec grep -HnoE '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' {} + \
| grep -vi 'example\.com\|your@\|test@\|@domain\|flowforge@toolyft.com'
}
The key patterns:
| Data Type | Regex Pattern | ||
| `[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}` | |||
| Phone | `\b[0-9]{3}[-.][0-9]{3}[-.][0-9]{4}\b` | ||
| API Key | `sk-[A-Za-z0-9]{10,}` or `AKIA[0-9A-Z]{16}` | ||
| IP Address | `\b([0-9]{1,3}\.){3}[0-9]{1,3}\b` | ||
| URL Creds | `https?://[^:]+:[^@]+@` | ||
| Company Name | `(client\ | company\ | vendor)\s[:=]\s[A-Z][A-Za-z]+` |
Equally important is what not to flag:
The script generates a timestamped markdown report:
# Privacy Scan Report — 2026-06-20 02:16
Target: /home/user/projects
## 📧 Non-Project Emails
✅ None found
## 🏢 Company / Client Names
✅ None found
---
✅ Result: CLEAN — no privacy issues detected
Reports are saved to `~/project-privacy-reports/report-YYYY-MM-DD.md` for historical tracking.
A `--quiet` flag makes the script return exit codes only — 0 for clean, 1+ for issues found. This is what cron and n8n use:
check-priv --quiet && echo "Clean" || echo "Issues found"
# Make executable
chmod +x scripts/check-privacy.sh
# Install as global command
sudo ln -sf $(pwd)/scripts/check-privacy.sh /usr/local/bin/check-priv
# Run your first scan
check-priv
# Quick check only
check-priv --quiet; echo "Exit: $?"
# View last report
check-priv --report
On first run, expect some false positives — that's normal. Add exclusions for:
Tune the exclusion lists in the script until `--quiet` returns 0. Then automation begins.
Add a weekly cron job to scan every Sunday at 3am:
# Open crontab
crontab -e
# Add this line:
0 3 * * 0 /usr/local/bin/check-priv --quiet && \
echo "[$(date)] ✅ Clean" >> /tmp/check-priv-history.log || \
echo "[$(date)] ⚠️ Issues found" >> /tmp/check-priv-history.log
The log file accumulates a running history:
[Sat Jun 20 03:00:01 UTC 2026] ✅ Clean
[Sat Jun 27 03:00:01 UTC 2026] ✅ Clean
[Sat Jul 4 03:00:01 UTC 2026] ⚠️ Issues found
No mail server needed. No external services. Just a log file you check when you remember — or better yet, integrate with n8n for alerts.
The weekly cron log is passive. Active alerts require a webhook that n8n can call, which then emails you when issues are found.
n8n (Docker container)
→ POST to host webhook server (port 9199)
→ check-priv runs on the host
→ Returns report JSON to n8n
→ If issues found: send email alert
If you already have a pipeline webhook server running (like the FlowForge publish pipeline), add a new endpoint:
# In your pipeline-webhook-server.py — add this handler
elif parsed.path == "/webhook/check-priv":
result = self._run_check_priv()
self._send_json(200, result)
The `_run_check_priv` method executes `/usr/local/bin/check-priv` and captures its output:
def _run_check_priv(self):
result = subprocess.run(
["/usr/local/bin/check-priv"],
capture_output=True, text=True, timeout=120
)
return {
"clean": result.returncode == 0,
"exit_code": result.returncode,
"report": result.stdout
}
The workflow has 4 nodes:
The HTTP Request node configuration:
URL: http://172.18.0.1:9199/webhook/check-priv
Method: POST
Headers:
X-Pipeline-Token: {{ $env.PIPELINE_TOKEN }}
When the scan finds issues, the email alert looks like:
Subject: ⚠️ Privacy Scan Alert — Issues Found
Body:
Privacy scan detected potential leaks in your project.
Run 'check-priv --report' on the server for full details.
Summary:
- 1 company/client name(s) flagged
- 1 credential reference(s) found
When the scanner reports issues, here's how to evaluate each category:
| Category | False Positive? | Real Issue? |
| `flowforge@toolyft.com` (your own domain) | `user@gmail.com` (personal email in a workflow) | |
| API Key | `sk-test-abc...` (test key in example code) | `sk-live-xyz...` (production key in a script) |
| Company Name | `company: Google` (public company in an article) | `company: ALSEC` (private client name in a dashboard) |
| n8n Cred ID | UUID like `abc123-...` (node reference) | Numeric ID like `"2"` (direct DB reference) |
| IP Address | `192.168.1.1` (private IP) | `203.0.113.5` (public server IP in docs) |
Recommended action by severity:
🔴 Critical — API keys, passwords, embedded URL creds → Rotate immediately, scrub from git history
🟡 High — Real emails, phone numbers, company names → Remove from public files, update dashboards
🟢 Low — n8n credential IDs, public IPs, false positives → Document and exclude from future scans
If you have multiple projects in a workspace directory, run the scanner from the parent:
check-priv /home/user/workspace
Or create a wrapper that scans each project individually and aggregates results:
for dir in /home/user/workspace/*/; do
check-priv "$dir" --quiet || echo "⚠️ Issues in $(basename $dir)"
done
Run the scanner as part of your deployment pipeline:
# Before deploy
if ! check-priv --quiet; then
echo "❌ Privacy scan failed — deploy blocked"
check-priv --report | mail -s "Privacy Blocked Deploy" team@project.com
exit 1
fi
This prevents any file with potential leaks from reaching production.
Replace the email node in n8n with a Slack webhook node or Microsoft Teams connector. Instead of email, the alert goes directly to your team chat:
n8n → IF (issues found) → Slack Webhook → #security-alerts
Your whole team sees the alert in seconds.
Add it to the exclusion list in the `check_emails` function:
| grep -vi 'you@yourproject.com\|admin@yourdomain.com'
The credential UUIDs in n8n workflows look like secrets but are just database row identifiers. The scanner already filters UUID patterns. If you still see false positives, add the specific credential IDs to the exclusion filter.
Check the cron log:
grep -i "check-priv" /var/log/syslog
Common issues:
The webhook server requires the auth token. Make sure the `X-Pipeline-Token` header matches what's configured in your systemd service file:
sudo grep PIPELINE_TOKEN /etc/systemd/system/flowforge-pipeline-webhook.service
Limit the file types or directories scanned. The biggest slowdown is usually `node_modules` — the script already excludes it. If scanning a very large repo, narrow the `find` scope:
# Only scan specific directories
find articles/ scripts/ n8n-workflows/ ...
Before automated scanning, privacy was a manual checklist you'd forget. You'd do a quick grep before a big launch, find nothing obvious, and call it done. The one time you missed something was the one time it mattered.
After automated scanning, privacy is a continuous process. Every Sunday at 3am, the scanner runs. If clean, you never hear about it. If not, you get an alert within seconds. The report archive gives you a paper trail. The n8n integration gives you active alerts.
| Before | After |
| Manual audit before launches | Continuous weekly scanning |
| Forget to check for months | Automated Sunday 3am schedule |
| No alert when leaks happen | Email/Slack alert within seconds |
| No historical record | Date-stamped report archive |
| One regex search, hope for the best | 8 specialized scan categories |
| No integration with automation | n8n webhook for CI/CD pipeline |
| Takes 2-3 hours per audit | 15 minutes setup, $0/mo forever |
Set it up once. Tune it for a week. Then forget about it — until the day it catches something that would have cost you thousands.
Get the full client intake pipeline — free, no credit card.
By downloading, you agree to our Privacy Policy. We'll send workflow updates — unsubscribe anytime.