Skip to main content

Safely removes sensitive information from pfSense config.xml exports

Project description

pfSense XML Configuration Redactor

The pfSense XML Configuration Redactor safely removes sensitive information from config.xml exports before they are shared with support, consultants, auditors, or AI tools for security analysis.

Installation

From PyPI (recommended)

pip install pfsense-redactor

Note: If you encounter an externally-managed-environment error (common on macOS and modern Linux distributions), use one of these alternatives:

Option 1: Install with pipx (recommended for CLI tools)

brew install pipx
pipx install pfsense-redactor

Option 2: Use a virtual environment

python3 -m venv venv
source venv/bin/activate
pip install pfsense-redactor

Option 3: Install in user space

pip install --user pfsense-redactor

From Source

git clone https://github.com/grounzero/pfsense-redactor.git
cd pfsense-redactor

Option 1: Development mode (recommended for contributing)

pip install -e .

Option 2: With virtual environment

python3 -m venv venv
source venv/bin/activate
pip install -e .

The tool preserves network architecture and routing logic whilst sanitising secrets and identifiers allowing safe troubleshooting and topology review without disclosing private data.

Keeps firewall and routing context
Removes passwords, keys, public IPs (optional), tokens, certs
Supports anonymisation for consistent placeholder mapping
Understands pfSense config structures, namespaces, VPNs, WireGuard, XML attributes, IPv6 zone IDs


Features

Protects real secrets

  • Passwords & encrypted passwords
  • Pre-shared keys (IPSec, OpenVPN, WireGuard)
  • TLS/OpenVPN static keys & certs
  • SNMP community strings
  • LDAP / RADIUS secrets
  • API keys & tokens
  • PEM blocks (RSA / EC / OpenSSH)

Preserves network logic

  • Subnets & masks (255.x.x.x always preserved)
  • Router topology
  • VLAN and VPN interfaces
  • Firewall rules and gateways

Smart redaction

Data Behaviour
Internal IPs Preserve with --keep-private-ips
Public IPs Mask or anonymise
Email addresses Mask or anonymise
URLs Preserve structure, mask hostname
MAC addresses Mask format-preserving
Certificates Collapse to [REDACTED_CERT_OR_KEY]

Operational modes

Mode Purpose
Default Safe redaction for sharing logs
--keep-private-ips Preserve private IPs (best for support/AI)
--anonymise Replace identifiers with consistent placeholders (IP_1, domain3.example)
--aggressive Scrub all fields (plugins/custom XML)

Requirements

  • Python 3.8+

Usage

Basic usage

# Output filename auto-generated as config-redacted.xml
pfsense-redactor config.xml

# Or specify output filename explicitly
pfsense-redactor config.xml redacted.xml

Preserve private IPs (recommended)

pfsense-redactor config.xml redacted.xml --keep-private-ips

Allow-list specific IPs and domains

# Preserve specific public services (never redact)
pfsense-redactor config.xml --allowlist-ip 8.8.8.8 --allowlist-domain time.nist.gov

# Preserve entire CIDR ranges
pfsense-redactor config.xml --allowlist-ip 203.0.113.0/24

# Use an allow-list file (supports IPs, CIDRs, and domains)
pfsense-redactor config.xml --allowlist-file my-allowlist.txt

Topology-safe anonymisation

pfsense-redactor config.xml redacted.xml --anonymise

Allow internal DNS names

pfsense-redactor config.xml redacted.xml --no-redact-domains --keep-private-ips

Aggressive mode

pfsense-redactor config.xml redacted.xml --aggressive

Dry run

# Show statistics only
pfsense-redactor config.xml --dry-run

# Show statistics with sample redactions (safely masked)
pfsense-redactor config.xml --dry-run-verbose

Output to STDOUT

pfsense-redactor config.xml --stdout > redacted.xml

In-place (danger)

pfsense-redactor config.xml --inplace --force

Allow-lists

Allow-lists let you preserve specific well-known IPs and domains that don't leak private information.

Default allow-list files

The tool automatically loads allow-lists from these locations (if they exist):

  1. .pfsense-allowlist in current directory
  2. ~/.pfsense-allowlist in home directory

To disable: use --no-default-allowlist

Allow-list file format

Create .pfsense-allowlist or use --allowlist-file:

# Comments start with #
# One item per line (IP, CIDR, or domain)

# Public DNS servers
8.8.8.8
1.1.1.1

# Cloud provider ranges
203.0.113.0/24
198.51.100.0/24

# NTP servers (suffix matching: preserves time.nist.gov and *.time.nist.gov)
time.nist.gov
pool.ntp.org

# Wildcard domains (*.example.org preserves all subdomains)
*.pfsense.org

See allowlist.example for a complete template.

CLI allow-list flags

# Add specific IPs or CIDR ranges (repeatable)
--allowlist-ip 8.8.8.8 --allowlist-ip 203.0.113.0/24

# Add specific domains (repeatable, case-insensitive, supports suffix matching)
--allowlist-domain time.nist.gov --allowlist-domain pool.ntp.org

# Load from file (supports IPs, CIDRs, and domains)
--allowlist-file /path/to/allowlist.txt

# Disable default file loading
--no-default-allowlist

Features:

  • CIDR support: 203.0.113.0/24 preserves all IPs in that range
  • Suffix matching: example.org preserves sub.example.org, db.corp.example.org, etc.
  • Wildcard domains: *.example.org is equivalent to suffix matching on example.org
  • IDNA/punycode: Automatically handles internationalised domains (e.g., bücher.examplexn--bcher-kva.example)
  • Merged sources: All CLI flags, files, and default files are combined

Note: Items in allow-lists are never redacted in:

  • Raw text IP/domain references
  • URL hostnames
  • Bare FQDNs

Example

Input

<openvpn>
  <server>
    <local>192.168.10.1</local>
    <tlsauth>-----BEGIN OpenVPN Static key-----ABC123...</tlsauth>
    <remote>198.51.100.10</remote>
    <remote_port>443</remote_port>
  </server>
</openvpn>

Output (--keep-private-ips)

<openvpn>
  <server>
    <local>192.168.10.1</local>
    <tlsauth>[REDACTED]</tlsauth>
    <remote>XXX.XXX.XXX.XXX</remote>
    <remote_port>443</remote_port>
  </server>
</openvpn>

Output (--anonymise)

<openvpn>
  <server>
    <local>IP_1</local>
    <tlsauth>[REDACTED]</tlsauth>
    <remote>IP_2</remote>
    <remote_port>443</remote_port>
  </server>
</openvpn>

Security Notes

Never restore the redacted file to pfSense.

Redacted output is for analysis only, because:

  • CDATA and comments are removed by XML parser
  • PEM blocks and binary data are collapsed
  • Some optional metadata fields may be stripped

Always keep the original secure copy.


Testing

Dry run summary

# Statistics only
pfsense-redactor config.xml --dry-run

# Statistics with sample redactions (safely masked to avoid leaks)
pfsense-redactor config.xml --dry-run-verbose

Sample output with --dry-run-verbose:

[+] Redaction summary:
    - Passwords/keys/secrets: 10
    - Certificates: 6
    - IP addresses: 26
    - Domain names: 47

[+] Samples of changes (limit N=5):
    IP: 198.51.***.42 → XXX.XXX.XXX.XXX
    IP: 2001:db8:*:****::1 → XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
    URL: https://198.51.***.42/admin → https://XXX.XXX.XXX.XXX/admin
    FQDN: db.***.example.org → example.com
    MAC: aa:bb:**:**:ee:ff → XX:XX:XX:XX:XX:XX
    Secret: p****************d (len=18) → [REDACTED]
    Cert/Key: PEM blob (len≈2048) → [REDACTED_CERT_OR_KEY]

Sample masking policy (prevents leaks in dry-run output):

  • IP: Keep first and last octet/segment, mask middle (e.g., 198.51.***.42)
  • URL: Show full URL but mask host as above
  • FQDN: Keep TLD and one left label, mask rest (e.g., db.***.example.org)
  • MAC: Mask middle octets (e.g., aa:bb:**:**:ee:ff)
  • Secret: Show length and first/last 2 chars only (e.g., p****************d (len=18))
  • Cert/Key: Just show placeholder with length (e.g., PEM blob (len≈2048))

Recommended test flags

Purpose Command
Support & AI review --keep-private-ips --no-redact-domains
Topology map w/o identifiers --anonymise
Nuke everything --aggressive

Stats example

[+] Redaction summary:
    - Passwords/keys/secrets: 4
    - Certificates: 2
    - IP addresses: 11
    - MAC addresses: 3
    - Domain names: 5
    - Email addresses: 1
    - URLs: 2

Contributing

Pull requests welcome. Particularly:

  • Additional pfSense element coverage
  • Plugin XML tag packs (WireGuard, pfBlockerNG, HAProxy, Snort, ACME, FRR)
  • Unit test configs

Licence

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pfsense_redactor-1.0.5.tar.gz (163.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pfsense_redactor-1.0.5-py3-none-any.whl (19.9 kB view details)

Uploaded Python 3

File details

Details for the file pfsense_redactor-1.0.5.tar.gz.

File metadata

  • Download URL: pfsense_redactor-1.0.5.tar.gz
  • Upload date:
  • Size: 163.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pfsense_redactor-1.0.5.tar.gz
Algorithm Hash digest
SHA256 1a49b324e432d251ba1418d98db81ebbe6aee3cac1d81fda987b5bf49e1f8c41
MD5 db6dbef2ad0eb64e6bfcd9f629afc72b
BLAKE2b-256 2dd41dd3d591b41d9bde7e7e28f670ee75651560d0bfe818b14fab3f51a26bbd

See more details on using hashes here.

Provenance

The following attestation bundles were made for pfsense_redactor-1.0.5.tar.gz:

Publisher: python-publish.yml on grounzero/pfsense-redactor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pfsense_redactor-1.0.5-py3-none-any.whl.

File metadata

File hashes

Hashes for pfsense_redactor-1.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 68ce9d3563cf993bad89649074e98b5e66feaa2297cfb41f2e31774e78ee9bba
MD5 280e6220a397a6796fa8d4f1bb5b8b5c
BLAKE2b-256 7f093bb492047a1c234efb5e6ace73cbf6675ee2b1bbe6cc6adad4c3d16d230d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pfsense_redactor-1.0.5-py3-none-any.whl:

Publisher: python-publish.yml on grounzero/pfsense-redactor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page