# pyobfus: the Python obfuscator

Obfuscate Python before you ship it—and still debug what you shipped.
简体中文 · Product · Documentation · PyPI
[](https://pypi.org/project/pyobfus/) [](https://pypi.org/project/pyobfus/) [](https://pyobfus.readthedocs.io/en/latest/) [-blue.svg)](https://github.com/zhurong2020/pyobfus/blob/main/LICENSE) [](https://www.python.org/downloads/) [](https://www.bestpractices.dev/projects/12788) [](https://doi.org/10.5281/zenodo.20846053) pyobfus is a local-first, AST-based Python obfuscator for Python 3.9–3.15. It obfuscates multi-file projects and packages as a whole: names are renamed consistently across modules and imports are rewritten to match, so Community output is still ordinary `.py` that runs without pyobfus installed. Keep the mapping file from the build private, and `pyobfus --unmap` turns a production traceback back into your original names, for you or an AI coding agent. Community is Apache-2.0, has no file or line limits, and requires no trial. > **v0.9.1:** `--unmap --trace-encoding` reads tracebacks saved in legacy > encodings such as cp1252 and reports undecodable input with exit 2 instead of > crashing; piped stdin now defaults to UTF-8. > > **What's new in v0.9.0:** `--unmap` now works for independent directory builds > (`--no-cross-file`). The mapping records names per file, so two files that reuse > the same short name restore to the right originals, frame by frame. Older > mappings keep working; older pyobfus versions reject the new mapping format > instead of guessing. See the > [debugging guide](https://github.com/zhurong2020/pyobfus/blob/main/docs/guides/debug-obfuscated-python.md) > and the [changelog](https://github.com/zhurong2020/pyobfus/blob/main/CHANGELOG.md). ## Why pyobfus | Advantage | What it means in practice | |---|---| | **Complete Community edition** | Obfuscate real projects without a file/line cap or trial clock. Optional limits are your CI safety rails, not an upgrade gate. | | **Diagnosable protection** | Keep the private mapping and restore identifiers in production tracebacks without giving customers the original source. | | **Evidence, not a black box** | Scan, preview, verify syntax, retain provenance and compare reproducible build reports. | | **Portable and local-first** | Source stays local and there is no telemetry ([what goes over the network](https://pyobfus.readthedocs.io/en/latest/NETWORK_BEHAVIOR/)); Community emits ordinary cross-platform Python without a native build matrix. | | **Explicit security claims** | Tested, verified-once and advisory-only claims are separated; deterrents are not presented as irreversible security. | ## Quick start ```bash pip install pyobfus # Check compatibility, preview, then build pyobfus --check src/ pyobfus src/ -o dist/ --dry-run --json pyobfus src/ -o dist/ --save-mapping mapping.json --verify-syntax # --verify-syntax only compiles the output; run your own tests against dist/ # Restore names when a production traceback arrives pyobfus --unmap --trace error.log --mapping mapping.json ``` In the next release, independent-file directory builds (`--no-cross-file`) also support `--save-mapping`. Their version-2 mapping resolves each traceback frame against its own file; names in excerpts and unframed logs stay unchanged. Use the new reader for these mappings; existing single-file and cross-file builds keep version 1. See the [debugging guide](https://github.com/zhurong2020/pyobfus/blob/main/docs/guides/debug-obfuscated-python.md#independent-file-directory-builds-next-release). Since 0.7.1, add opt-in `--verify-names` to check newly unbound globals without execution. Success JSON reports partial coverage explicitly; see [name verification](https://pyobfus.readthedocs.io/en/latest/NAME_VERIFICATION/) for usage and limits. Check the final directory or wheel with `pyobfus --check-delivery dist/ --json` before shipping. For framework presets, configuration discovery, packaging and verification, start at the [task-oriented documentation](https://pyobfus.readthedocs.io/). ## Minimal example Input: ```python def greet(name): message = f"Hello, {name}!" return message print(greet("world")) ``` Run `pyobfus input.py -o output.py`. Representative Community output: ```python def I0(I1): I2 = f"Hello, {I1}!" return I2 print(I0("world")) ``` Both print `Hello, world!`. Generated identifiers can differ with input and configuration; verify the exact output with your own tests. Keep a mapping when you need to restore names from a shipped traceback. Parameter names are preserved by default in every preset. Explicit `--no-preserve-param-names` or YAML `preserve_param_names: false` keeps legacy renaming with a warning: keyword calls may raise `TypeError` or silently bind incorrectly. Rebuild from original source and keep the new mapping with the new artifact; mapping numbers can change and old mappings cannot decode rebuilt output. Cross-file directory builds (the default) still preserve parameters; legacy `--no-cross-file` directory builds follow the option. ## Features at a glance Community includes name mangling with import rewriting across a project (directories also rename function locals; parameters and methods remain unchanged there; single files also rename methods and preserve parameters by default, see the [guide](https://pyobfus.readthedocs.io/en/latest/guides/protect-python-before-selling/#what-you-get-measured)), string and numeric transforms, framework-aware presets, config-aware pre-flight scanning (including coarse hardcoded-secret screening without displaying values), SARIF, structured dry-run, reverse traceback mapping, syntax verification, provenance, reproducible output and verifiable build reports. Professional adds four kinds of commercial value: - **Protection strength:** AES encryption, control-flow flattening, dead-code injection, anti-debugging, Selective Opacity and sealing. - **Protected assets:** import strings, embedded data, Runtime String Vault and protected tracebacks. - **Distribution control:** device, expiry, run-count, platform and application-supplied-key policies. - **Accountability:** forensic watermarking and buyer-specific builds. The durable classification rule is documented in the [Community / Pro boundary policy](https://github.com/zhurong2020/pyobfus/blob/main/docs/EDITION_BOUNDARY_POLICY.md). ## 🔌 Companion MCP server: `pyobfus-mcp` Install the MCP server with no API key and no source upload: ```bash uvx pyobfus-mcp # or: pip install pyobfus-mcp ``` It exposes structured tools for scanning, configuration, protection, verification, preset explanation, tier recommendations and traceback mapping. See the [MCP package guide](https://github.com/zhurong2020/pyobfus/tree/main/pyobfus_mcp) and its registration in the [official MCP Registry](https://registry.modelcontextprotocol.io/). ### Agent and editor integrations - `pyobfus-review` and `pyobfus-protect` skills separate read-only review from build-producing work. See [skills](https://github.com/zhurong2020/pyobfus/tree/main/skills). - The [VS Code extension](https://marketplace.visualstudio.com/items?itemName=zhurong2020.pyobfus) provides inline risk diagnostics and traceback reversal; it is also on [Open VSX](https://open-vsx.org/extension/zhurong2020/pyobfus). - [`zhurong2020/pyobfus-action@v1`](https://github.com/marketplace/actions/pyobfus-scan-and-build) runs scans or verified builds in GitHub Actions with SARIF support. - The stable JSON CLI includes reason codes and an `ai_hint` next action. - Agent-readable project facts are published in [`llms.txt`](https://github.com/zhurong2020/pyobfus/blob/main/llms.txt), while contributor instructions live in [`AGENTS.md`](https://github.com/zhurong2020/pyobfus/blob/main/AGENTS.md). All Agent guidance is public and human-auditable. pyobfus does not serve hidden instructions or different facts based on User-Agent. ## Configuration Generate a starting configuration or use a named preset: ```bash pyobfus --init src/ pyobfus src/ -o dist/ --preset django pyobfus --list-presets ``` Community presets include `safe`, `balanced`, `aggressive`, `fastapi`, `django`, `flask`, `pydantic`, `click`, `sqlalchemy` and `ml`. See the [documentation home](https://pyobfus.readthedocs.io/) and [`pyobfus --help`](https://github.com/zhurong2020/pyobfus/blob/main/pyobfus/cli.py) for current options. Optional `max_files` and `max_total_loc` values are user-selected safety limits at every tier. ## How do I debug an obfuscated crash with an AI assistant? Build with `--save-mapping mapping.json`, keep that file private, then run: ```bash pyobfus --unmap --trace error.log --mapping mapping.json ``` The restored identifiers can be read by you or an AI assistant without giving the customer your mapping or original source. `--trace-marker` can also stamp generated files with the exact recovery command. ## Purchase Professional Edition Professional Edition is **$45 USD, one time**—not a subscription. A five-day trial requires no registration or card: ```bash pyobfus-trial start ``` The trial is an honor-system convenience control, not a security boundary. Visit the [product and purchase page](https://zhurong2020.github.io/pyobfus/#purchase-professional-edition) for current payment methods, refund terms and purchase steps. After purchase, use the [license activation guide](https://pyobfus.readthedocs.io/en/latest/LICENSE_ACTIVATION_GUIDE/). Runtime-backed Pro artifacts depend on the separately redistributable, pure-Python `pyobfus-runtime` package. Target machines do not need the complete proprietary builder or a licence key. ## Security and limitations Obfuscation raises the cost of inspection; it does not make client-side Python irreversible. Runtime-decrypted material can be observed by a determined attacker. Keep credentials and authorization decisions behind environment, secret-manager or server boundaries. - [Threat model](https://pyobfus.readthedocs.io/en/latest/THREAT_MODEL/) - [Support matrix](https://pyobfus.readthedocs.io/en/latest/SUPPORT_MATRIX/) - [Release provenance](https://github.com/zhurong2020/pyobfus/blob/main/docs/RELEASE_PROVENANCE_VERIFICATION.md) - [Security policy](https://github.com/zhurong2020/pyobfus/blob/main/SECURITY.md) ## Comparison and deployment guides - [Comparison overview](https://pyobfus.readthedocs.io/en/latest/COMPARISON/) - [vs PyArmor](https://pyobfus.readthedocs.io/en/latest/compare/pyarmor/) - [vs Nuitka](https://pyobfus.readthedocs.io/en/latest/compare/nuitka/) - [PyInstaller cookbook](https://pyobfus.readthedocs.io/en/latest/PYINSTALLER_COOKBOOK/) - [Compiled-packaging cookbook](https://github.com/zhurong2020/pyobfus/blob/main/docs/COMPILED_PACKAGING_COOKBOOK.md) - [Integration testing](https://pyobfus.readthedocs.io/en/latest/INTEGRATION_TESTING/) ## Architecture and development The product line separates the Apache-2.0 Core, proprietary Pro builder, redistributable runtime, MCP package, editor extension and GitHub Action. See: - [Project structure](https://pyobfus.readthedocs.io/en/latest/PROJECT_STRUCTURE/) - [Contributing guide](https://github.com/zhurong2020/pyobfus/blob/main/CONTRIBUTING.md) - [Developer instructions](https://github.com/zhurong2020/pyobfus/blob/main/AGENTS.md) - [Changelog](https://github.com/zhurong2020/pyobfus/blob/main/CHANGELOG.md) ## Community and citation Use [GitHub Issues](https://github.com/zhurong2020/pyobfus/issues) for bugs and [Discussions](https://github.com/zhurong2020/pyobfus/discussions) for questions and ideas. Citation metadata is in [`CITATION.cff`](https://github.com/zhurong2020/pyobfus/blob/main/CITATION.cff), with archival DOI [10.5281/zenodo.20846053](https://doi.org/10.5281/zenodo.20846053). Core is Apache-2.0; Professional implementation is proprietary. See [`LICENSE-NOTICE.md`](https://github.com/zhurong2020/pyobfus/blob/main/LICENSE-NOTICE.md).