1. Introduction
GuardSpine's main job is AI-aware code governance—using AI models to automatically review pull requests and create cryptographic proof of those reviews. However, because GuardSpine sends code to third-party AI models (like Claude or GPT) to be reviewed, there is a massive risk. Sensitive information—like passwords and personal data (PII)—must be stopped from leaking to these AI providers. You cannot let personal data poison third-party AI models.
To solve this, the GuardSpine team turned to PII-Shield: a lightning-fast, open-source Go engine designed to find and redact sensitive data. The big engineering challenge was figuring out how to integrate this powerful external Go dependency into GuardSpine's strictly Python-based ecosystem. We had to make sure the integration was 100% secure (no data could accidentally leak to the internet) and extremely fast.
We had to make a choice. Should we run the Go tool as a normal program using Python's subprocess.run? Should we deploy a local server? Or, should we try something newer and run the Go code straight inside Python using WebAssembly (WASM)? This article explains how we tested normal programs against WebAssembly to adapt PII-Shield for this AI pipeline, the problems we found with slow startup times, and when you should use each method.
2. WebAssembly (WASI) Integration: The Sandboxed Approach
WebAssembly (WASM) is great for adding tools into Python. Its biggest benefit is that it works anywhere. Instead of building different versions of the tool for Linux, Mac, and Windows, we only need to build one .wasm file. Any computer running wasmtime can use it. Also, WASM is very secure because it runs in a "sandbox." This means the Go tool is locked inside and cannot access your network or your hard drive.
To make this work, we built a Python script (pii_wasm_client.py). When we need to hide data, this script starts the WASM engine. It passes important settings (like the secret PII_SALT password) safely using environment variables. Then, it uses temporary files to send the data into the WASM tool and get the clean text back.
import wasmtime
import os
# 1. Setup the Engine (Turn on the computer)
engine = wasmtime.Engine()
# 2. Load the Code (Load the program)
module = wasmtime.Module.from_file(engine, "pii-shield-wasi.wasm")
# 3. Setup the Rules (Configure WASI)
linker = wasmtime.Linker(engine)
linker.define_wasi()
# 4. Create a Safe Workspace (Create a Store)
store = wasmtime.Store(engine)
wasi = wasmtime.WasiConfig()
wasi.inherit_stdout()
store.set_wasi(wasi)
# 5. Run the Program
instance = linker.instantiate(store, module)
_start = instance.exports(store)["_start"]
try:
_start(store)
except wasmtime.ExitTrap:
pass # Expected exit
When we explain this to business leaders, they usually ask these important security questions:
"Why not just use a paid API on the internet?" Because the WASM tool runs locally on your machine, your code never leaves your private network.
"How do you keep the secret salt (PII_SALT) safe?" The secret is passed directly into the locked WASM sandbox. Because the sandbox is blocked off, nothing outside of it can steal the secret.
"Why not just use simple search patterns (Regex)?" Simple search patterns are fast but easily break on weird data, often flagging safe text as secrets by mistake (false positives). PII-Shield uses smart tokenization and entropy scoring to find real secrets, which requires a strong Go engine, not just simple text matching.
3. Real-World Benchmarks & The Bottlenecks
When we started, we thought running the WASM tool directly inside Python would be faster than asking the computer (OS) to start a whole new external program (subprocess.run).
To test this, we built a script to run the tool 10,000 times (you can find the open-source benchmark.py script in this public GitHub Gist). The text we tested was very small: just a 100-character JSON string. We compared a normal Linux program against the WASM engine.
The results were surprising. In our test with the tiny text, the normal program was about 4.7x faster:
- Normal Program (
subprocess.run): ~0.86 ms per run. - Starting and running the WASM Engine: ~4.03 ms per run.
Even when scaled to 100,000 iterations, the per-execution latency remained rock-solid (0.85ms vs 4.05ms). The execution time scaled perfectly linearly, proving that while WASM carries a strict 4ms "cold start" tax, it introduces absolutely no memory leaks or degraded performance over time—a crucial metric for GuardSpine's stability.
But saying "WASM is slower" is not fair. WebAssembly code is actually very fast. The problem was the "Cold Start"—how long it takes to turn the tool on. We found three big slowdowns:
First, Starting Go is Slow. Every time we ran the WASM tool, the Go language had to start up its memory manager and background tasks inside the sandbox. When you run a normal program, your computer’s Operating System does this almost instantly. In WASM, we had to wait for it every single time.
Second, The File Speed Problem (I/O). To send text into the WASM tool, our Python script created temporary files on the hard drive. Creating, writing, and deleting files takes a lot of time and caused about 30-50% of the delay.
Finally, The Text Was Too Small. Because our test text was only 100 characters, 99% of the time was spent just turning the tool on and managing files. The actual work of finding the secrets took almost zero time. If we tested a massive 10MB file instead, the 4x speed difference would likely disappear because the real work (finding secrets) would take much longer than the startup time.
4. Unlocking WASM's True Potential
Even though the "Cold Start" is slow, we shouldn't give up on WASM's amazing security and portability. To make WASM lightning-fast, we need to change how we run it:
The easiest fix is Keeping It Running. Our test turned the WASM tool on and off 10,000 times. If we turn it on just once when the server starts, we never have to wait for the Go startup delay again. WASM would be just as fast as a normal program.
Next, we must fix the slow files by using In-Memory Pipes. Instead of writing data to real files on the hard drive, we can push the data directly through standard in-memory streams (pipes). This fixes the file speed problem easily.
The perfect, final goal is Shared Memory. Instead of copying text back and forth, Python and WASM can look at the exact same spot in the computer's memory. This is the fastest possible way to share data, though it introduces complex engineering challenges, such as safely managing Go's Garbage Collector across the Python-WASM boundary.
Finally, we should look at TinyGo. The normal Go compiler adds a lot of heavy, extra background tasks. TinyGo is a smaller compiler made just for WASM. Using it would make the tool much smaller and make it start up 10 to 20 times faster.
5. The Verdict: When to use which?
Even though normal programs start faster, speed isn't the only thing that matters—security and stability matter too. The hidden superpower of WASM is that Python is in total control. If Python crashes, the WASM tool dies cleanly with it. If you use subprocess.run, a crashed Python app might leave behind "zombie" programs that eat up your server's resources.
So, when should you use a Normal Program? They are best for things you run rarely, like a command-line developer tool or a script that runs once an hour. The computer's Operating System is great at starting them quickly. While proper process management in Python can mitigate risks, WASM remains inherently safer for memory lifecycles.
When should you use WASM? WASM is the undisputable winner for modern, always-on Cloud servers. When you need to run untrusted code safely, or you need your tool to work on any operating system without building 10 different versions, WASM is unbeatable. It guarantees that your code stays locked in a safe box.
6. Conclusion
Integrating PII-Shield into GuardSpine taught us a lot about the trade-offs between raw speed and safe, modern design. While normal programs won the simple speed test, adapting WebAssembly gave the platform unmatched security and the ability to run anywhere without complex cross-compilation.
As the platform's processing volume scales, the roadmap for this integration is clear. We need to stop turning the WASM tool on and off for every log line. Instead, the plan is to keep the engine running persistently, compile it with TinyGo, and share memory directly across the Python-WASM boundary. The ultimate goal isn't just to match the speed of normal programs, but to beat them completely, creating a lightning-fast, unbreakable redaction layer for AI development.



Top comments (0)