Skip to content

Commit 715c871

Browse files
SecAI-Hubclaude
andcommitted
Add multi-GPU support (NVIDIA/AMD/Intel/Apple) and Tor-routed web search
GPU support: - Auto-detection at first boot via detect-gpu.sh (CUDA > ROCm > MPS > XPU > Vulkan > CPU) - Diffusion worker supports all PyTorch backends (CUDA, ROCm, MPS, XPU, CPU) - Inference worker Containerfile supports CUDA, ROCm, Vulkan, CPU build variants - Systemd units allow /dev/kfd (AMD ROCm) alongside existing NVIDIA/Intel DRI devices - BlueBuild recipe includes mesa/Vulkan drivers, Tor, SearXNG packages - appliance.yaml gains gpu.backend config (default: auto) Tor-routed web search: - Search mediator service: sanitizes outbound queries (strips PII), cleans inbound results (strips HTML, detects prompt injection), builds LLM context - Self-hosted SearXNG configured to route all traffic through Tor SOCKS5 - Only privacy-respecting engines enabled (DuckDuckGo, Wikipedia, StackOverflow, GitHub) - Disabled by default — user must enable in policy.yaml and start services - offline-only session mode hard-blocks search even if enabled - Every search audit-logged (query hash only, not raw content) - UI gains /api/search and /api/chat/search endpoints for search-augmented chat - 27 new tests covering PII stripping, injection detection, result sanitization - 82 total Python tests passing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 7b4b35b commit 715c871

13 files changed

Lines changed: 1041 additions & 2 deletions

File tree

README.md

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ Built on [uBlue](https://universal-blue.org/) (Fedora Atomic / Silverblue) with
4040
| Inference Worker | 8465 | llama.cpp | LLM inference (CUDA / ROCm / Vulkan / Metal / CPU) |
4141
| Diffusion Worker | 8455 | Python | Image and video generation (CUDA / ROCm / XPU / MPS / CPU) |
4242
| Quarantine | -- | Python | 7-stage verify, scan, and promote pipeline |
43+
| Search Mediator | 8485 | Python | Sanitized web search (query PII stripping + result cleaning) |
44+
| SearXNG | 8888 | Python | Self-hosted metasearch engine (privacy-respecting engines only) |
45+
| Tor | 9050 | C | Anonymous SOCKS5 proxy (all searches routed through Tor) |
4346

4447
## Hardware Support
4548

@@ -389,6 +392,46 @@ To disable the airlock again:
389392
sudo systemctl stop secure-ai-airlock
390393
```
391394

395+
### Web Search (Tor-Routed, Optional)
396+
397+
Web search is **disabled by default**. When enabled, the LLM can augment its answers with web search results — all routed through Tor for anonymity.
398+
399+
**How it works:**
400+
1. The LLM generates a search query (your raw prompt never leaves the device)
401+
2. The search mediator strips PII (emails, phone numbers, SSNs, API keys, IPs) from the query
402+
3. The sanitized query goes to a local SearXNG instance
403+
4. SearXNG routes the search through Tor (your IP is hidden from search engines)
404+
5. Results come back through Tor, are stripped of HTML/scripts, and checked for prompt injection
405+
6. Clean results are injected as context for the LLM to formulate a better answer
406+
7. The UI shows a "web sources used" indicator with citations
407+
408+
**To enable:**
409+
410+
```bash
411+
# Enable in policy first
412+
# Edit /etc/secure-ai/policy/policy.yaml and set search.enabled: true
413+
414+
# Start the search stack (Tor -> SearXNG -> Search Mediator)
415+
sudo systemctl start secure-ai-tor
416+
sudo systemctl start secure-ai-searxng
417+
sudo systemctl start secure-ai-search-mediator
418+
```
419+
420+
**Privacy protections:**
421+
- All traffic routed through Tor (IP hidden from search engines)
422+
- Only privacy-respecting engines enabled (DuckDuckGo, Wikipedia, StackOverflow, GitHub)
423+
- PII automatically stripped from outbound queries
424+
- Queries with >50% PII content are blocked entirely
425+
- Inbound results scanned for prompt injection attacks
426+
- Every search is audit-logged (query hash only, not raw content)
427+
- `offline-only` session mode hard-blocks all search even if enabled
428+
429+
**To disable:**
430+
431+
```bash
432+
sudo systemctl stop secure-ai-search-mediator secure-ai-searxng secure-ai-tor
433+
```
434+
392435
---
393436

394437
## Security Overview
@@ -421,6 +464,7 @@ Every model — whether downloaded from the catalog or imported by the user —
421464
| **Models** | 7-stage quarantine: source, format, integrity, provenance, static scan, behavioral test, diffusion scan |
422465
| **Tools** | Default-deny policy, path allowlisting, traversal protection, rate limiting |
423466
| **Egress** | Airlock disabled by default, PII/credential scanning, destination allowlist |
467+
| **Search** | Tor-routed, PII stripped from queries, injection detection on results, audit logged |
424468
| **Services** | Systemd sandboxing: ProtectSystem=strict, PrivateNetwork, syscall filters |
425469
| **GPU Isolation** | Vendor-specific DeviceAllow (NVIDIA `/dev/nvidia*`, AMD `/dev/kfd`, Intel `/dev/dri/*`), PrivateNetwork on all |
426470
| **Emergency** | Panic switch: instant network kill + route flush + service stop |
@@ -514,6 +558,19 @@ quarantine:
514558
smoke_test_max_critical: 1 # fail if >1 critical flag
515559
```
516560

561+
**Web search** (`policy/policy.yaml`):
562+
```yaml
563+
search:
564+
enabled: false # disabled by default
565+
strip_pii: true # always strip PII from queries
566+
detect_injection: true # scan results for prompt injection
567+
audit: true # log every search (hash only)
568+
allowed_engines: # privacy-respecting engines only
569+
- duckduckgo
570+
- wikipedia
571+
- stackoverflow
572+
```
573+
517574
**Tool firewall policy** (`policy/policy.yaml`):
518575
```yaml
519576
tools:
@@ -550,9 +607,11 @@ services/
550607
quarantine/ Python -- 7-stage verification + scanning pipeline
551608
inference-worker/ llama.cpp wrapper
552609
diffusion-worker/ Python -- Stable Diffusion image/video generation
610+
search-mediator/ Python -- Tor-routed web search with PII stripping
553611
ui/ Python/Flask -- Web UI (chat, generate, model management)
554612
tests/
555613
test_pipeline.py Quarantine pipeline tests (48 tests)
614+
test_search.py Search mediator tests (27 tests)
556615
test_ui.py Web UI tests (7 tests)
557616
docs/
558617
threat-model.md Formal threat model and security invariants
@@ -566,7 +625,7 @@ cd services/registry && go test -v -race ./...
566625
cd services/tool-firewall && go test -v -race ./...
567626
cd services/airlock && go test -v -race ./...
568627
569-
# Python tests (55 total)
628+
# Python tests (82 total)
570629
pip install pytest flask requests pyyaml
571630
python -m pytest tests/ -v
572631
@@ -585,7 +644,9 @@ shellcheck files/system/usr/libexec/secure-ai/*.sh files/scripts/*.sh
585644
- [x] **M6 Hardening** -- Systemd sandboxing, kernel params, nftables, panic switch
586645
- [x] **M7 CI/CD** -- GitHub Actions, Go/Python tests, shellcheck, YAML validation
587646
- [x] **M8 Image/Video Generation** -- Diffusion worker, one-click downloads, generate UI
588-
- [ ] **M9 Polish** -- OPA/Rego policy engine, appliance setup wizard, documentation site
647+
- [x] **M9 Multi-GPU Support** -- NVIDIA/AMD/Intel/Apple auto-detection, Vulkan fallback
648+
- [x] **M10 Tor-Routed Search** -- SearXNG + Tor, PII stripping, injection detection, audit
649+
- [ ] **M11 Polish** -- OPA/Rego policy engine, appliance setup wizard, documentation site
589650

590651
## Troubleshooting
591652

files/scripts/build-services.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,27 @@ mkdir -p "$DIFFUSION_DIR"
6363
cp /tmp/services/diffusion-worker/app.py "$DIFFUSION_DIR/app.py"
6464
echo " -> ${DIFFUSION_DIR}/app.py"
6565

66+
# Search mediator
67+
echo "Installing: search-mediator"
68+
SEARCH_DIR="/opt/secure-ai/services/search-mediator"
69+
mkdir -p "$SEARCH_DIR"
70+
cp /tmp/services/search-mediator/app.py "$SEARCH_DIR/app.py"
71+
cat > "${INSTALL_DIR}/search-mediator" <<'WRAPPER'
72+
#!/usr/bin/env python3
73+
import sys
74+
sys.path.insert(0, "/opt/secure-ai/services/search-mediator")
75+
from app import main
76+
main()
77+
WRAPPER
78+
chmod +x "${INSTALL_DIR}/search-mediator"
79+
echo " -> ${INSTALL_DIR}/search-mediator"
80+
81+
# Install SearXNG via pip if not available as RPM
82+
echo "Installing: searxng"
83+
pip3 install --prefix=/usr --no-cache-dir searxng 2>/dev/null || \
84+
pip3 install --prefix=/usr --break-system-packages --no-cache-dir searxng 2>/dev/null || \
85+
echo "WARNING: searxng pip install failed, relying on RPM package"
86+
6687
# Cleanup build artifacts
6788
rm -rf "$SRC_DIR"
6889
dnf remove -y golang 2>/dev/null || true

files/system/etc/secure-ai/config/appliance.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ services:
4141
bind: "127.0.0.1:8490"
4242
diffusion:
4343
bind: "127.0.0.1:8455"
44+
search_mediator:
45+
bind: "127.0.0.1:8485"
46+
searxng:
47+
bind: "127.0.0.1:8888"
48+
tor:
49+
socks: "127.0.0.1:9050"
4450

4551
session:
4652
mode: "normal" # normal | sensitive | offline-only

files/system/etc/secure-ai/policy/policy.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,31 @@ tools:
6565
- name: "process.spawn"
6666
- name: "filesystem.delete"
6767

68+
search:
69+
# Tor-routed web search via self-hosted SearXNG
70+
# Disabled by default — user must explicitly enable
71+
enabled: false
72+
# Maximum query length sent to SearXNG (after PII stripping)
73+
max_query_length: 200
74+
# Maximum results returned per search
75+
max_results: 5
76+
# Maximum context size injected into LLM (characters)
77+
max_context_length: 4000
78+
# PII scanning on outbound queries (always on)
79+
strip_pii: true
80+
# Block queries that are >50% redacted PII
81+
block_high_pii_queries: true
82+
# Injection detection on inbound results
83+
detect_injection: true
84+
# Audit every search (query hash + sanitized query + result count)
85+
audit: true
86+
# Search engines enabled in SearXNG (privacy-respecting only)
87+
allowed_engines:
88+
- duckduckgo
89+
- wikipedia
90+
- stackoverflow
91+
- github
92+
6893
airlock:
6994
enabled: false
7095
allowed_destinations:
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Secure AI Appliance - SearXNG Configuration
2+
# Self-hosted metasearch engine. All outbound requests route through Tor.
3+
# Listens on localhost only — accessed by the search mediator service.
4+
5+
general:
6+
instance_name: "SecAI Search"
7+
debug: false
8+
enable_metrics: false
9+
10+
server:
11+
bind_address: "127.0.0.1"
12+
port: 8888
13+
secret_key: "secai-local-only-key"
14+
# No public access — localhost only
15+
limiter: false
16+
# Disable public image proxy (no need, we strip images)
17+
image_proxy: false
18+
19+
search:
20+
safe_search: 1
21+
default_lang: "en"
22+
autocomplete: false
23+
# Max results per engine
24+
max_results: 10
25+
26+
# Route ALL outbound requests through Tor SOCKS5 proxy
27+
outgoing:
28+
proxies:
29+
all://:
30+
- socks5h://127.0.0.1:9050
31+
# Timeout per engine request (Tor adds latency)
32+
request_timeout: 20
33+
useragent_suffix: ""
34+
35+
# Only enable privacy-respecting search engines
36+
engines:
37+
# Web search
38+
- name: duckduckgo
39+
engine: duckduckgo
40+
shortcut: ddg
41+
disabled: false
42+
43+
- name: wikipedia
44+
engine: wikipedia
45+
shortcut: wp
46+
disabled: false
47+
48+
- name: wikidata
49+
engine: wikidata
50+
shortcut: wd
51+
disabled: false
52+
53+
# Programming / technical
54+
- name: stackoverflow
55+
engine: stackoverflow
56+
shortcut: so
57+
disabled: false
58+
59+
- name: github
60+
engine: github
61+
shortcut: gh
62+
disabled: false
63+
64+
- name: arch wiki
65+
engine: archlinux
66+
shortcut: aw
67+
disabled: false
68+
69+
# Disable all engines that require API keys or track users
70+
- name: google
71+
engine: google
72+
disabled: true
73+
74+
- name: bing
75+
engine: bing
76+
disabled: true
77+
78+
- name: yahoo
79+
engine: yahoo
80+
disabled: true
81+
82+
- name: brave
83+
engine: brave
84+
disabled: true
85+
86+
# Disable analytics, tracking, result collection
87+
ui:
88+
static_use_hash: true
89+
default_theme: simple
90+
results_on_new_tab: false
91+
92+
# No external plugins
93+
plugins: []
94+
95+
# Privacy-focused defaults
96+
enabled_plugins:
97+
- "Hash plugin"
98+
- "Hostname replace"
99+
- "Tracker URL remover"
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Secure AI Appliance - Tor configuration
2+
# Provides anonymous SOCKS5 proxy for SearXNG search routing.
3+
# Only SearXNG connects to Tor — no other services have access.
4+
5+
# SOCKS5 proxy for SearXNG
6+
SocksPort 127.0.0.1:9050
7+
8+
# Disable direct connections (SOCKS only)
9+
SocksPolicy accept 127.0.0.1
10+
SocksPolicy reject *
11+
12+
# Circuit isolation: each destination gets its own circuit
13+
IsolateDestAddr 1
14+
IsolateDestPort 1
15+
16+
# New circuit for each SearXNG query batch (rotate every 60s)
17+
NewCircuitPeriod 60
18+
MaxCircuitDirtiness 600
19+
20+
# Disable unused features
21+
ControlPort 0
22+
DNSPort 0
23+
24+
# Logging (minimal — don't log query content)
25+
Log notice file /var/lib/secure-ai/logs/tor.log
26+
SafeLogging 1
27+
28+
# Data directory
29+
DataDirectory /var/lib/secure-ai/tor
30+
31+
# Hardened security settings
32+
Sandbox 1
33+
NoExec 1
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
[Unit]
2+
Description=Secure AI Appliance - Search Mediator (Sanitized Web Search)
3+
After=secure-ai-searxng.service
4+
Wants=secure-ai-searxng.service
5+
6+
[Service]
7+
Type=simple
8+
ExecStart=/usr/libexec/secure-ai/search-mediator
9+
Restart=on-failure
10+
RestartSec=5
11+
12+
Environment=BIND_ADDR=127.0.0.1:8485
13+
Environment=SEARXNG_URL=http://127.0.0.1:8888
14+
Environment=APPLIANCE_CONFIG=/etc/secure-ai/config/appliance.yaml
15+
Environment=POLICY_PATH=/etc/secure-ai/policy/policy.yaml
16+
Environment=AUDIT_DIR=/var/lib/secure-ai/logs
17+
18+
# Sandboxing — mediator only talks to SearXNG on localhost
19+
ProtectSystem=strict
20+
ReadWritePaths=/var/lib/secure-ai/logs
21+
ReadOnlyPaths=/etc/secure-ai
22+
PrivateTmp=yes
23+
ProtectHome=yes
24+
ProtectKernelTunables=yes
25+
ProtectKernelModules=yes
26+
ProtectControlGroups=yes
27+
NoNewPrivileges=yes
28+
RestrictSUIDSGID=yes
29+
30+
# Only needs localhost network (to reach SearXNG)
31+
RestrictAddressFamilies=AF_INET AF_UNIX
32+
33+
# No GPU, no devices
34+
PrivateDevices=yes
35+
36+
# Resource limits
37+
MemoryMax=256M
38+
TasksMax=64
39+
40+
[Install]
41+
WantedBy=multi-user.target

0 commit comments

Comments
 (0)