<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Labyrinx</title>
    <description>The latest articles on DEV Community by Labyrinx (@labyrinx).</description>
    <link>https://dev.to/labyrinx</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3987430%2F2c118663-26ba-4d11-b593-b41403da692a.png</url>
      <title>DEV Community: Labyrinx</title>
      <link>https://dev.to/labyrinx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/labyrinx"/>
    <language>en</language>
    <item>
      <title>How to Protect Python Code in 2026 — Obfuscation, Compilation, and Encryption That Actually Works</title>
      <dc:creator>Labyrinx</dc:creator>
      <pubDate>Thu, 18 Jun 2026 03:04:25 +0000</pubDate>
      <link>https://dev.to/labyrinx/how-to-protect-python-code-in-2026-obfuscation-compilation-and-encryption-that-actually-works-2912</link>
      <guid>https://dev.to/labyrinx/how-to-protect-python-code-in-2026-obfuscation-compilation-and-encryption-that-actually-works-2912</guid>
      <description>&lt;p&gt;Python ships as readable source code. Even when bundled into an EXE, well-known extraction tools recover your source in under a minute. If you're selling desktop Python software, distributing internal tools, or shipping code you'd rather not hand over as plaintext — you need protection.&lt;/p&gt;

&lt;p&gt;After spending months building a Python code protection tool (Labyrinx), here's what I learned about what actually works — and what doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 30-Second Attack
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Attacker recovers your entire source in under a minute:&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; pyinstxtractor your_app.exe       &lt;span class="c"&gt;# extracts .pyc bytecode&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; uncompyle6 extracted/main.pyc      &lt;span class="c"&gt;# decompiles to readable Python&lt;/span&gt;
&lt;span class="c"&gt;# Output: your original source. Names, strings, comments — everything.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't a Python flaw. Interpreted languages are inherently open. Protection means adding layers that each make reverse engineering harder.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Four Levels of Python Code Protection
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Level 1: Obfuscation (Free)
&lt;/h3&gt;

&lt;p&gt;Rename every variable, function, and class to random tokens. Strip comments and docstrings. The code runs identically but reads like gibberish.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Before
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_discount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_tier&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_tier&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;premium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;

&lt;span class="c1"&gt;# After name obfuscation
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_x7f3a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_a1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_a2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_a2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;_l_s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x17&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_a1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Stops:&lt;/strong&gt; Casual reading. A competitor opening your &lt;code&gt;.py&lt;/code&gt; file.&lt;br&gt;
&lt;strong&gt;Doesn't stop:&lt;/strong&gt; Anyone with a debugger. Names are cosmetic.&lt;/p&gt;
&lt;h3&gt;
  
  
  Level 2: Compilation to Native Code
&lt;/h3&gt;

&lt;p&gt;Python → C translation → C compiler → &lt;code&gt;.pyd&lt;/code&gt; (native x64 shared library). No bytecode to decompile. An attacker gets assembly, not Python.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Native compilation example&lt;/span&gt;
cython my_module.pyx
cl.exe /LD my_module.c /I Python313/include
&lt;span class="c"&gt;# Output: my_module.cp313-win_amd64.pyd  ← assembly, not bytecode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Stops:&lt;/strong&gt; &lt;code&gt;pycdc&lt;/code&gt;, &lt;code&gt;uncompyle6&lt;/code&gt;, every Python decompiler.&lt;br&gt;
&lt;strong&gt;Doesn't stop:&lt;/strong&gt; &lt;code&gt;strings.exe&lt;/code&gt; finds every string literal. An experienced reverse engineer can trace the assembly.&lt;/p&gt;
&lt;h3&gt;
  
  
  Level 3: String and Module Encryption (AES-256)
&lt;/h3&gt;

&lt;p&gt;Encrypt every string literal so &lt;code&gt;strings.exe&lt;/code&gt; finds nothing. Encrypt entire modules so they're opaque ciphertext on disk.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Before encryption&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; strings.exe my_app.pyd | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"api_key"&lt;/span&gt;
sk-proj-4f8a3b2c1d9e6f7a8b3c2d1e9f6a7b8c  &lt;span class="c"&gt;# ← found!&lt;/span&gt;

&lt;span class="c"&gt;# After AES-256 string encryption&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; strings.exe my_app.pyd | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"api_key"&lt;/span&gt;
&lt;span class="c"&gt;# Nothing. Every string encrypted at rest.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Stops:&lt;/strong&gt; Static analysis tools, &lt;code&gt;strings.exe&lt;/code&gt;, disk forensics.&lt;br&gt;
&lt;strong&gt;Doesn't stop:&lt;/strong&gt; A memory dump captured at the exact moment of decryption.&lt;/p&gt;
&lt;h3&gt;
  
  
  Level 4: Code Virtualization (Custom VM)
&lt;/h3&gt;

&lt;p&gt;Replace Python bytecode with a custom bytecode that only a custom VM understands. The VM's instruction set is &lt;strong&gt;randomized per build&lt;/strong&gt; — reversing one build teaches nothing about the next.&lt;/p&gt;

&lt;p&gt;Instead of &lt;code&gt;import my_module&lt;/code&gt; loading standard Python bytecode, it loads instructions for a VM only Labyrinx can interpret. The opcode for "add" is &lt;code&gt;0x4F&lt;/code&gt; in build #1 and &lt;code&gt;0x93&lt;/code&gt; in build #2.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stops:&lt;/strong&gt; Every standard reverse engineering tool. IDA Pro and Ghidra understand x64 — not Labyrinx VM bytecode.&lt;br&gt;
&lt;strong&gt;Doesn't stop:&lt;/strong&gt; A dedicated attacker who traces the VM interpreter itself. This takes weeks, not seconds.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Stack in Practice: Labyrinx
&lt;/h2&gt;

&lt;p&gt;I built Labyrinx to chain all four levels:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source → Name Obfuscation → Control Flow Flattening → String Encryption
  → Module Encryption → Cython → MSVC → .pyd → Custom VM → Output Folder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is a self-contained folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MyApp/
├── MyApp.exe              ← 30 KB launcher
├── python313.dll          ← embedded Python (no install)
├── my_app.pyd             ← your code (6 layers deep)
└── Lib/site-packages/     ← dependencies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Zip it and ship it. No Python install required on the target machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Folders, Not Single EXEs
&lt;/h2&gt;

&lt;p&gt;I used single-file EXE bundlers for years. Every other release, customers emailed: "Your app is a virus!" Antivirus heuristics flag packed EXEs. Labyrinx outputs a clean folder — plain &lt;code&gt;.pyd&lt;/code&gt; files and a tiny launcher. No packing, no temp extraction, no false positives.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Labyrinx Compares to Other Approaches
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Labyrinx (Enterprise)&lt;/th&gt;
&lt;th&gt;Bytecode Obfuscation&lt;/th&gt;
&lt;th&gt;C-to-Native Compilation&lt;/th&gt;
&lt;th&gt;Transpiler EXE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Name obfuscation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;String encryption&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ AES-256&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Native compilation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ .pyd&lt;/td&gt;
&lt;td&gt;❌ bytecode&lt;/td&gt;
&lt;td&gt;✅ .pyd&lt;/td&gt;
&lt;td&gt;✅ EXE&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code VM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ randomized&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Anti-debug&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ multi-point&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;License system&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ built-in&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AV-friendly&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️ (packed EXE)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pricing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$29/mo&lt;/td&gt;
&lt;td&gt;$49-$199&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Full comparison: &lt;a href="https://labyrinx-dev.github.io/compare/" rel="noopener noreferrer"&gt;labyrinx-dev.github.io/compare/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What No Tool Can Do
&lt;/h2&gt;

&lt;p&gt;Nothing is unbreakable. The CPU must execute your logic eventually, and a debugger can trace it. The realistic goal is making reverse engineering &lt;strong&gt;more expensive than rewriting&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Raw &lt;code&gt;.py&lt;/code&gt;: 0 seconds&lt;/li&gt;
&lt;li&gt;Bytecode obfuscation (free tier): A few hours (known decryptor approach)&lt;/li&gt;
&lt;li&gt;C-to-native compilation: A few days (assembly, not bytecode)&lt;/li&gt;
&lt;li&gt;Labyrinx Enterprise: Weeks+ (6 layers: native code + AES-256 strings + flattened control flow + encrypted modules + custom VM + anti-debug + integrity hashes)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For 99% of potential attackers, that's enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free:&lt;/strong&gt; &lt;a href="https://labyrinx-dev.github.io/" rel="noopener noreferrer"&gt;Download Labyrinx&lt;/a&gt; — Freemium mode includes name obfuscation + Cython compilation at no cost&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro ($9/mo):&lt;/strong&gt; String encryption, module encryption, license system&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise ($29/mo):&lt;/strong&gt; AES-256, custom VM, anti-debug, PYD integrity hashes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://labyrinx-dev.github.io/" rel="noopener noreferrer"&gt;labyrinx-dev.github.io&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Comparison guide:&lt;/strong&gt; &lt;a href="https://labyrinx-dev.github.io/compare/" rel="noopener noreferrer"&gt;labyrinx-dev.github.io/compare/&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Email:&lt;/strong&gt; &lt;a href="mailto:labyrinx@yahoo.com"&gt;labyrinx@yahoo.com&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What protection strategies have you tried for shipping Python apps? What worked and what didn't?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>security</category>
      <category>tutorial</category>
      <category>cython</category>
    </item>
    <item>
      <title>Labyrinx — Obfuscate Python, compile to native x64, and ship as a self-contained app</title>
      <dc:creator>Labyrinx</dc:creator>
      <pubDate>Tue, 16 Jun 2026 12:41:41 +0000</pubDate>
      <link>https://dev.to/labyrinx/labyrinx-obfuscate-python-compile-to-native-x64-and-ship-as-a-self-contained-app-l59</link>
      <guid>https://dev.to/labyrinx/labyrinx-obfuscate-python-compile-to-native-x64-and-ship-as-a-self-contained-app-l59</guid>
      <description>&lt;p&gt;Labyrinx is a desktop tool that takes a Python project, obfuscates the source through multiple layers, compiles it to native x64 machine code, and produces a self-contained folder your customers can just double-click. No Python install, no terminal, no dependencies to manage.&lt;/p&gt;

&lt;p&gt;The problem&lt;br&gt;
Shipping a Python app to a customer means either:&lt;/p&gt;

&lt;p&gt;Handing over readable source code&lt;br&gt;
Making them install Python and dependencies&lt;br&gt;
Or spending days figuring out PyInstaller, Cython, and distribution yourself&lt;br&gt;
And even with Cython alone, strings.exe still dumps every string literal. Decompilers like pycdc recover your logic structure.&lt;/p&gt;

&lt;p&gt;Before and after&lt;br&gt;
Here's what happens to a simple piece of code:&lt;/p&gt;

&lt;h1&gt;
  
  
  Before
&lt;/h1&gt;

&lt;p&gt;API_KEY = "sk-abc123"&lt;br&gt;
def connect():&lt;br&gt;
    return requests.post("&lt;a href="https://api.example.com" rel="noopener noreferrer"&gt;https://api.example.com&lt;/a&gt;",&lt;br&gt;
        headers={"Authorization": f"Bearer {API_KEY}"})&lt;br&gt;
Freemium (free): After name obfuscation + Cython compilation, strings.exe returns nothing readable. Variable names are randomized. Control flow is restructured. Not Fort Knox, but no longer plaintext.&lt;/p&gt;

&lt;p&gt;Enterprise ($29/mo): The decompiler sees a single AES-256 encrypted blob. The bytecode inside runs on a custom VM with per-build randomized instruction sets. Raising the bar from casual inspection to serious reverse-engineering effort.&lt;/p&gt;

&lt;p&gt;Protection layers&lt;br&gt;
Layer   Freemium    Pro Enterprise&lt;br&gt;
Name obfuscation    ✅ ✅ ✅&lt;br&gt;
Control flow flattening — ✅ ✅&lt;br&gt;
String AES encryption   — ✅ ✅&lt;br&gt;
Module encryption (compressed)  — ✅ —&lt;br&gt;
Module encryption (AES-256) — — ✅&lt;br&gt;
Anti-debug  — — ✅&lt;br&gt;
Custom VM (per-build randomized)    — — ✅&lt;br&gt;
License system (HWID, expiry, tiers)    — ✅ ✅&lt;br&gt;
Tech stack&lt;br&gt;
Python 3.13 → Cython → MSVC → native x64 .pyd&lt;br&gt;
Import tracer automatically discovers project dependencies and site-packages&lt;br&gt;
Embedded Python 3.13 runtime in the output folder&lt;br&gt;
HWID-bound signed license keys with expiry and tier enforcement&lt;br&gt;
Per-build randomized VM instruction sets (Enterprise)&lt;br&gt;
Runs entirely on your machine — no cloud, no phoning home&lt;br&gt;
Honest limitations&lt;br&gt;
No obfuscation is unbreakable. This isn't DRM — it raises the cost of reverse engineering from trivial to prohibitive. Also: Windows-only for now, Cython build times scale with project size, and dynamic imports (importlib, plugin systems) may need manual dependency configuration.&lt;/p&gt;

&lt;p&gt;Who this is for&lt;br&gt;
Developers selling desktop Python apps, distributing internal tools, or shipping software where readable source is a concern. Not for open-source projects.&lt;/p&gt;

&lt;p&gt;Free tier is fully functional. Pro ($9/mo) and Enterprise ($29/mo) add stronger encryption and the custom VM.&lt;/p&gt;

&lt;p&gt;Website: labyrinx-dev.github.io&lt;/p&gt;

&lt;p&gt;Feedback welcome — what would make this useful for your projects?&lt;/p&gt;

</description>
      <category>security</category>
      <category>python</category>
      <category>showdev</category>
      <category>cython</category>
    </item>
  </channel>
</rss>
