How Protection Works¶
This topic provides a high-level overview of the PyLocket protection pipeline — from uploading your artifact to running the protected application on an end-user's machine.
Protection Pipeline Overview¶
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Upload │───→│ Analyze │───→│ Protect │───→│ Package │
│ Artifact │ │ Bytecode │ │Functions │ │ Output │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
Stage 1: Upload¶
When you run pylocket protect, the CLI:
- Validates the artifact type (executable, wheel, zip, etc.)
- Uploads the artifact to PyLocket's secure cloud storage (encrypted at rest)
- Creates a protection job in the queue
Stage 2: Bytecode Analysis¶
The protection worker:
- Identifies the packaging format (PyInstaller, cx_Freeze, Briefcase, wheel, or ZIP)
- Extracts all Python bytecode from the artifact
- Enumerates every function, method, and class body in the code
Stage 3: Function-Level Protection¶
Each discovered function is individually encrypted using PyLocket's proprietary protection pipeline. The original function body is replaced with a lightweight stub that delegates to the secure native runtime. This process ensures that the original logic is never present in plaintext within the distributed artifact.
Stage 4: Packaging¶
The protected output is assembled:
- The modified artifact (with stub-replaced functions)
- The encrypted function data
- A signed protection manifest (
.pylocket_manifest) - The native runtime (
_pylocket_rt.pyd/.so) - Bootstrap code (injected into the application's startup path)
Stub Replacement¶
Original Python function:
After protection, a decompiler sees:
The stub: - Preserves the function signature (name, arguments, decorators) - Replaces only the function body - Calls the native runtime with the function's unique ID - Reveals nothing about the original logic
Each protected build uses randomized stub variations, so no two builds have the same stub fingerprint. Automated tools cannot pattern-match stubs across different builds.
Runtime Execution¶
When a protected application launches:
- The bootstrap module loads the native runtime
- The runtime verifies the protection manifest's cryptographic signature
- The application prompts for license activation (or validates a cached token)
- On success, the application runs normally — protected functions are decrypted on demand as they are called
The native runtime handles all decryption, integrity verification, and security checks transparently. From the application's perspective, protected functions behave identically to their unprotected originals.
What Gets Protected (and What Doesn't)¶
Protected¶
- All Python function bodies (functions, methods, lambdas, comprehensions)
- Class bodies
- Module-level code (the
__init__code object)
Not Protected¶
- Non-Python files (images, configs, data files, HTML templates)
- C extension modules (
.pyd,.sofiles compiled from C/Cython) - String literals in function signatures and docstrings (these remain in stubs)
- Module names and directory structure
__pycache__files (these are recreated by the stubs)
Note: If you need to protect non-Python data, encrypt it at the application level and decrypt it in your protected Python code.
See Also¶
- Protection — What gets protected
- Security Model — Security architecture overview
- Performance — Runtime performance information