In Part 2, we demonstrated that even vendor-hardened system prompts collapse under adversarial framing. Relying on the model to police itself is an architectural failure.
The solution is architectural decoupling: moving the security boundary outside of the context window into an external Security Gateway.
In this third installment of our Hands-On AI Security series, we explore the Blue Team side of the lab: building our Flask security proxy (secure_gateway.py), configuring hot-reloading ingress rules in filter_rules.py, and implementing egress Data Loss Prevention (DLP).
The Gateway Architecture
The security gateway acts as a reverse proxy sitting directly between the user’s browser and the Ollama inference engine:
sequenceDiagram
autonumber
actor User as Client Browser
participant GW as Flask Gateway (secure_gateway.py)
participant Rules as Filter Rules (filter_rules.py)
participant LLM as Ollama (Piper Engine)
User->>GW: POST /chat (User Prompt)
GW->>Rules: Check Ingress Rules (Regex / Blacklist)
alt Ingress Trigger Match (e.g., 'override_admin')
Rules-->>GW: Match Found (Blocked)
GW-->>User: 403 Blocked: Prompt flagged by security policy
else Ingress Clean
Rules-->>GW: Pass
GW->>LLM: Forward Prompt to Ollama :11434
LLM-->>GW: Raw Completion Response
GW->>Rules: Check Egress Rules (Secret Leak Prevention)
alt Egress Secret Detected (e.g., 'NP-ADMIN-')
Rules-->>GW: Redact / Mask Secret
GW-->>User: Response Delivered with Secrets Masked: [REDACTED_TOKEN]
else Egress Clean
GW-->>User: Deliver Raw Response
end
end
Inspecting filter_rules.py
In the lab repository, security logic is contained in lab/scripts/filter_rules.py.
Ingress Filtering (Pre-Inference)
The gateway inspects incoming user text for known exploit patterns before forwarding the payload to Ollama:
| |
Egress Data Masking (Post-Inference DLP)
Even if an attacker crafts an novel, obfuscated prompt that bypasses ingress detection, the egress filter provides defense-in-depth by inspecting the model’s output before it returns to the user:
| |
The Pedagogical Design: “Calibrated Incomplete”
One deliberate choice in this lab is that the default rules in filter_rules.py are intentionally incomplete.
If we provided a 100% airtight ruleset on Day 1, students wouldn’t learn. Instead, obfuscated prompts (e.g., base64 encoding or spaced letters d b - i n t e r n a l) slip past the default filters. Students must analyze the failure, open filter_rules.py, write their own regex patterns, and watch the gateway hot-reload instantly.
Testing Ingress and Egress with Curl
You can test both ingress blocking and egress redaction directly from your terminal:
| |
Up Next in the Series
Static regex filters are a great first step, but enterprise engineering teams cannot maintain thousands of hardcoded strings against semantic evasion.
In Part 4: Enterprise Policy-as-Code with Open Policy Agent (OPA) (releasing Thursday, October 1), we integrate OPA, classify prompt intent with local LLMs, and enforce declarative Rego policies.
The complete open-source lab materials, security gateway code, and Docker Compose stack are available in the SixFiveMil/Securing-AI GitHub repository.