Skip to main content

safestream-redactor

PyPI Python License

Detect and redact PII and credentials in text files of any size, with constant memory. The file is streamed in chunks, so a 100 GB log uses the same memory as a 1 KB one. Bytes outside a redacted span, line endings included, are left exactly as they were.

Requirements

  • Python 3.10 or newer, on Linux, macOS or Windows.
  • No third-party runtime dependencies (tomli only on Python 3.10). Optional extras are listed below.

Installation

pip install safestream-redactor

Only need the command-line tool? Install it into an isolated environment with pipx:

pipx install safestream-redactor

Check the install:

safestream --version                # prints e.g. "safestream 0.4.0"
python -m safestream_redactor --version

Optional extras

Extra Install Adds
ner pip install 'safestream-redactor[ner]' then python -m spacy download en_core_web_sm spaCy person / organisation / location detection (--ner)
onnx pip install 'safestream-redactor[onnx]' On-device ONNX NER model (--onnx MODEL.onnx --onnx-vocab VOCAB.json); you supply the model
ui pip install 'safestream-redactor[ui]' Local web playground (safestream ui, Streamlit)

An optional compiled (Rust) core gives the same output as the pure-Python pattern and labeled-identifier tiers, 3-12x faster on the project's evaluation corpora; enable it with Redactor(backend="native"). Its wheel is not on PyPI yet, so build it from source (needs a Rust toolchain):

pip install "safestream-redactor-native @ git+https://github.com/MounishSenisetty/SafeStream-Redactor#subdirectory=native"

Without it, backend="native" falls back to pure Python with a warning.

Upgrade or remove:

pip install --upgrade safestream-redactor
pip uninstall safestream-redactor

Command-line usage

The package installs one command, safestream, with six subcommands:

Command What it does
safestream redact INPUT -o OUTPUT Redact a file, a directory, or stdin (-)
safestream detect INPUT... List what would be redacted, without changing anything
safestream init-config Print a documented starter policy file (TOML)
safestream serve Run a local REST API (standard library only)
safestream mcp-serve Run a local Model Context Protocol server over stdio
safestream ui Open the local web playground (needs the ui extra)

Run safestream <command> --help for the full option list.

redact

# redact everything detectable
safestream redact input.txt -o output.txt

# only some entity types, with a custom replacement
safestream redact input.txt -o output.txt --types email,ssn --replace "***"

# keep the last 4 characters visible
safestream redact cards.csv -o masked.csv --mode mask --keep-last 4

# consistent keyed tokens, e.g. <EMAIL_75e802c7c314f5a2> (same input -> same token)
safestream redact input.txt -o output.txt --mode pseudonymize --hmac-key "$SECRET"

# per-type replacement text, plus your own words and regexes
safestream redact input.txt -o output.txt --replace-type email='<EMAIL>' \
    --custom-word ProjectX --custom-regex 'INT-\d+'

# stdin to stdout
cat app.log | safestream redact - -o -

# a whole directory, in parallel; print counts and write a JSON report
safestream redact logs/ -o redacted/ --workers 4 --stats --report run.json

Example:

$ printf 'contact bob@corp.io, ssn: 123-45-6789\n' | safestream redact - -o -
contact [REDACTED], ssn: [REDACTED]

--report FILE writes counts and sizes only, never the matched text.

detect

safestream detect app.log                     # human-readable list (no secret text)
safestream detect app.log --json              # one JSON object per detection
safestream detect src/*.py --sarif > out.sarif  # SARIF 2.1.0
safestream detect . --fail-on-detect          # exit status 1 if anything is found
safestream detect app.log --show-text         # also print the matched text (local only)
$ safestream detect app.log
app.log:3:7: email  conf=0.95
app.log:9:12: ssn  conf=1.00
-- 2 detection(s) (matched text hidden; --show-text reveals it)

init-config

safestream init-config -o policy.toml
safestream redact input.txt -o output.txt --config policy.toml

Flags given on the command line override the file. Unknown keys are rejected.

[detection]
# types = ["email", "ssn", "credit_card"]   # omit for all types
min_confidence = 0.5
use_ner = false
use_entropy = true

[redaction]
mode = "replace"                            # replace | mask | pseudonymize
replacement = "[REDACTED]"
mask_keep_last = 4

[redaction.replacements]
# email = "<EMAIL>"

[custom]
# words = ["ProjectX"]
# patterns = ['\\binternal-[a-z]+\\b']

serve

safestream serve                     # http://127.0.0.1:8000 (loopback only)
safestream serve --port 9000 --config policy.toml --max-body 1048576
curl -s -X POST http://127.0.0.1:8000/redact \
  -H 'Content-Type: application/json' \
  -d '{"text": "email bob@corp.io"}'
# {"redacted": "email [REDACTED]", "total_detections": 1, "detections_by_type": {"email": 1}}

Endpoints: GET /health, GET /version, GET /detectors, POST /redact, POST /scan. Request bodies are never logged.

mcp-serve

Exposes the tools scan, redact, explain_detection, detectors and health to an MCP client over stdio. Register it in your client's configuration as:

{ "command": "safestream", "args": ["mcp-serve"] }

ui

Opens an interactive playground in your browser (requires the ui extra):

pip install 'safestream-redactor[ui]'
safestream ui                          # http://127.0.0.1:8501

Paste text or upload a .txt, .log, .json or .csv file, up to 2 GB by default (--max-upload-mb). Uploads over 5 MiB are redacted by the parallel streaming engine and previewed, and the redacted file can be saved to a folder. Streamlit holds an upload in memory (about twice its size) while it is selected. Detect highlights findings by severity, with a table of types, confidence and line:col locations. Redact shows the original and sanitized text side by side (replace, mask, or keyed hash) and lets you download the result. Inspect replays the streaming engine one sliding window at a time. It shows the context, emitted, and carried bands, and how an entity that a chunk boundary would cut is kept whole. The page listens on 127.0.0.1 only, with Streamlit usage statistics off and the offline network guard on. A banner confirms these settings, or warns when they are missing.

Common options (redact and detect)

Option Meaning
--types a,b,c Only detect these entity types (default: all)
--config FILE Load a TOML policy file
--min-confidence X Drop detections scoring below X (default 0.5)
--custom-word W, --custom-regex R Always redact these (repeatable)
--no-entropy Turn off generic high-entropy secret detection
--ner, --onnx MODEL.onnx Enable an NER tier (needs its extra)
--encoding ENC Input/output encoding (default utf-8)
--workers N Parallel workers (directories, or one large file)
--memory-limit SIZE Stay within a memory budget, e.g. 256MiB
--enable-plugins Load third-party detector plugins (off by default)
--allow-network Turn off the network guard (see below)
--offline-hard MODE Linux only: kernel-enforced offline mode (seccomp, netns, auto)

Redaction options (redact only): --mode {replace,mask,pseudonymize}, --replace TEXT, --replace-type TYPE=TEXT, --keep-last N, --mask-char C, --hmac-key KEY. Mask mode never leaves more than half of a value visible, so a short value is never shown in full.

Detection options (detect only): --json, --sarif, --fail-on-detect, and --show-text / --reveal-matches (also print the matched text, which is hidden by default so detect output is safe to log; for local triage only). detect accepts files and directories; directories are walked recursively, skipping symlinks, .git/, and binary files.

While redact or detect runs, an in-process guard blocks outbound (non-loopback) network connections by default. On Linux, --offline-hard adds a kernel-enforced block on top.

Exit status

Code Meaning
0 Success
1 Runtime error (e.g. unreadable input, invalid config), or detect --fail-on-detect found something
2 Invalid command-line usage (unknown option, missing argument)
3 The run could not fit in --memory-limit

Entity types

Group Types
Personal data email, phone, credit_card, ssn, ipv4, ipv6, dob, id_number
Credentials aws_key, aws_secret, github_token, api_key, jwt, private_key, slack_token, slack_webhook, stripe_key, google_api_key, sendgrid_key, twilio_key, npm_token, openai_key, anthropic_key, url_credentials
Generic secrets secret (high-entropy strings with no known format)
Names (needs ner or onnx) person, org, loc
Your own custom (from --custom-word / --custom-regex)

Python API

from safestream_redactor import EntityType, RedactionPolicy, Redactor

redactor = Redactor()
redactor.redact("email bob@corp.io, ssn: 123-45-6789")
# 'email [REDACTED], ssn: [REDACTED]'

# inspect without redacting
[(d.entity_type.value, d.text) for d in redactor.detect("mail bob@corp.io from 10.0.0.1")]
# [('email', 'bob@corp.io'), ('ipv4', '10.0.0.1')]

# choose types and how they are rewritten
Redactor(types=["email"]).redact("bob@corp.io 123-45-6789")
# '[REDACTED] 123-45-6789'
policy = RedactionPolicy(replacements={EntityType.EMAIL: "<EMAIL>"})
Redactor(policy=policy).redact("write to bob@corp.io")
# 'write to <EMAIL>'
Redactor(policy=RedactionPolicy(mode="mask", mask_keep_last=4)).redact("card 4111 1111 1111 1111")
# 'card ***************1111'

# your own words and patterns
Redactor(custom_words=["ProjectX"], custom_patterns=[r"INT-\d+"]).redact("ProjectX ticket INT-42")
# '[REDACTED] ticket [REDACTED]'

# file to file with constant memory; the output is written atomically
stats = redactor.redact_file("huge.log", "huge.redacted.log")
stats.summary()   # '2 detection(s): email=1, ssn=1'

# split one large file across processes (same output as a single process)
redactor.redact_file("huge.log", "huge.redacted.log", workers=8)

# any iterable of text chunks (a socket, a generator, a file object)
with open("app.log", newline="") as source:
    for piece in redactor.redact_stream(source):
        print(piece, end="")

Adding a detector from another package

A package can add a detection tier by declaring an entry point. Plugins are opt-in: enable them with Redactor(load_plugins=True), --enable-plugins, or [plugins] enabled = true (a warning names any installed plugin that was not loaded):

[project.entry-points."safestream_redactor.detectors"]
my_detector = "my_package.detectors:MyDetector"

A detector is any object with a name attribute and a detect(text) -> list[Detection] method.

Limitations

Structured data (e-mails, cards, SSNs, keys, tokens) is detected with high precision. Names and street addresses in free prose are only detected with the ner or onnx extra, and even then on a best-effort basis. Review redacted output before sharing it where a miss would be costly.

License

MIT

Metadata

Release files for safestream-redactor 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for safestream-redactor 0.5.0
File Size Uploaded Provenance Actions
safestream_redactor-0.5.0.tar.gz 176.0 kB With provenance Details for safestream_redactor-0.5.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for safestream-redactor 0.5.0
File Interpreter ABI Platform Actions
safestream_redactor-0.5.0-py3-none-any.whl Python 3 none any Details for safestream_redactor-0.5.0-py3-none-any.whl

Total release size: 375.4 kB

Release files / safestream_redactor-0.5.0.tar.gz

Download URL safestream_redactor-0.5.0.tar.gz
Size 176.0 kB
Tags Source
SHA-256 checksum
How to use checksums
75bd4a175b8ec1284ea97d5225e76e1bb2789b51479d11c45d2f3ba9605b373e
BLAKE2b-256 checksum
How to use checksums
562d522c99a407df789d6d4301482db8958472e35f47de2cf1c53fdc7bc4ff25
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

Release files / safestream_redactor-0.5.0-py3-none-any.whl

Download URL safestream_redactor-0.5.0-py3-none-any.whl
Size 199.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5fba28c7379ac2902abb7de8c8afe342bb7390b583d5af28913e1bff0d5b950b
BLAKE2b-256 checksum
How to use checksums
ab38a71eaedf5683a87d99c42691e189225e346dbfa305c477501fc31edca5c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

Security for safestream-redactor 0.5.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for safestream_redactor-0.5.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page