An OpenClaw hook that integrates Google Cloud Model Armor for real-time sanitization of LLM inputs and outputs.
Intercepts messages flowing through OpenClaw and sends them to Model Armor for analysis against five filter categories:
| Filter | Detects |
|---|---|
| Responsible AI (RAI) | Hate speech, harassment, sexually explicit, dangerous content |
| Sensitive Data Protection (SDP) | PII, credentials, API keys, financial data |
| Prompt Injection & Jailbreak (PI) | Injection attacks, jailbreak attempts |
| Malicious URIs | Phishing links, malware URLs |
| CSAM | Child safety violations (always on) |
Two enforcement modes:
inspect(default) β log warnings, allow message throughblockβ log warnings, clear content, push warning message to user
- π Fail-open design β API errors never block your messages
- π Flexible auth β SA JSON key (with optional domain-wide delegation) or
gcloudCLI fallback - π¦ Zero dependencies β uses native
fetch()and Node.jscrypto - β‘ Token caching β access tokens cached for 55 minutes
- π Auto-chunking β long messages split for PI filter's 512-token limit
# 1. Clone the hook
git clone https://github.com/miticojo/openclaw-hook-model-armor.git \
~/.openclaw/hooks/model-armor
# 2. Set required env vars (add to your shell profile or deployment)
export MODEL_ARMOR_PROJECT="your-gcp-project-id"
export MODEL_ARMOR_TEMPLATE="your-template-id"
# 3. Enable the hook
openclaw hooks enable model-armor
# 4. Verify
openclaw hooks list # should show β ready for model-armorThat's it β all messages will now be screened by Model Armor.
- OpenClaw installed and running
- A Google Cloud project with billing enabled
gcloudCLI or a service account JSON key
gcloud services enable modelarmor.googleapis.com --project=YOUR_PROJECTThe identity calling Model Armor needs the modelarmor.user role:
# For a service account:
gcloud projects add-iam-policy-binding YOUR_PROJECT \
--member="serviceAccount:YOUR_SA@YOUR_PROJECT.iam.gserviceaccount.com" \
--role="roles/modelarmor.user"
# For your user account (if using gcloud auth):
gcloud projects add-iam-policy-binding YOUR_PROJECT \
--member="user:you@example.com" \
--role="roles/modelarmor.user"Via GCP Console β Security β Model Armor, or via CLI:
gcloud model-armor templates create my-guardrail \
--project=YOUR_PROJECT \
--location=europe-west4 \
--rai-settings-filters='[
{"filterType":"HATE_SPEECH","confidenceLevel":"MEDIUM_AND_ABOVE"},
{"filterType":"HARASSMENT","confidenceLevel":"MEDIUM_AND_ABOVE"},
{"filterType":"SEXUALLY_EXPLICIT","confidenceLevel":"HIGH"},
{"filterType":"DANGEROUS","confidenceLevel":"MEDIUM_AND_ABOVE"}
]' \
--pi-and-jailbreak-filter-settings-enforcement=ENABLED \
--pi-and-jailbreak-filter-settings-confidence-level=LOW_AND_ABOVE \
--malicious-uri-filter-settings-enforcement=ENABLED \
--basic-config-filter-enforcement=ENABLEDNote the template ID (e.g., my-guardrail).
git clone https://github.com/miticojo/openclaw-hook-model-armor.git \
~/.openclaw/hooks/model-armor# Required
export MODEL_ARMOR_PROJECT="your-project-id"
export MODEL_ARMOR_TEMPLATE="your-template-id"
# Optional
export MODEL_ARMOR_LOCATION="europe-west4" # default; or us-central1
export MODEL_ARMOR_ENFORCE="inspect" # default; or "block"
export MODEL_ARMOR_SKIP_DIRECT="false" # skip private/DM chats
export MODEL_ARMOR_MAX_LENGTH="50000" # max chars to sanitize
# Authentication (pick one):
# Option A β Service account JSON key (recommended for containers)
export MODEL_ARMOR_SA_KEY_PATH="/path/to/service-account.json"
export MODEL_ARMOR_IMPERSONATE_USER="user@example.com" # optional: domain-wide delegation
# Option B β gcloud CLI (for local dev)
# Just have `gcloud auth login` done; no extra env vars neededopenclaw hooks enable model-armor# Check the hook is loaded
openclaw hooks list
# You should see: β ready β π‘οΈ model-armor
# Send a test message to your agent, then check the GCP Console:
# Security β Model Armor β Monitoring β interactions should incrementIf you run OpenClaw on Kubernetes with a ConfigMap-based openclaw.json:
β οΈ Important:openclaw hooks enablewrites to the PVC copy ofopenclaw.json. If your init container copies the ConfigMap to the PVC on every restart, the hook enablement will be lost. You must add the hooks config to your ConfigMap source:
{
"hooks": {
"internal": {
"enabled": true,
"entries": {
"model-armor": {
"enabled": true
}
}
}
}
}Add the env vars to your Deployment manifest:
env:
- name: MODEL_ARMOR_PROJECT
value: "your-project-id"
- name: MODEL_ARMOR_TEMPLATE
value: "your-template-id"
- name: MODEL_ARMOR_LOCATION
value: "europe-west4"
- name: MODEL_ARMOR_ENFORCE
value: "inspect"
- name: MODEL_ARMOR_SA_KEY_PATH
value: "/path/to/mounted/service-account.json"
- name: MODEL_ARMOR_IMPERSONATE_USER
value: "user@example.com"| Variable | Required | Default | Description |
|---|---|---|---|
MODEL_ARMOR_PROJECT |
Yes | β | GCP project ID |
MODEL_ARMOR_TEMPLATE |
Yes | β | Model Armor template ID |
MODEL_ARMOR_LOCATION |
No | europe-west4 |
GCP region |
MODEL_ARMOR_ENFORCE |
No | inspect |
inspect or block |
MODEL_ARMOR_SKIP_DIRECT |
No | false |
Skip private/direct chats |
MODEL_ARMOR_MAX_LENGTH |
No | 50000 |
Max chars to sanitize |
MODEL_ARMOR_SA_KEY_PATH |
No | β | Path to SA JSON key file |
MODEL_ARMOR_IMPERSONATE_USER |
No | β | Email for domain-wide delegation |
message:receivedβ callssanitizeUserPromptβ screens incoming user messagesmessage:sentβ callssanitizeModelResponseβ screens outgoing agent responses- Text longer than 2000 chars is chunked for the PI filter's 512-token limit
- Auth tokens are cached for 55 minutes (GCP tokens expire after 60 min)
- On any error, the hook fails open β logs the error and allows the message through
Model Armor offers a free tier of 2 million tokens/month. After that, it's $0.10 per 1 million tokens. See Model Armor pricing.
us-central1europe-west4
- 512-token limit on prompt injection detection β long messages are chunked automatically
- Text-only β does not scan tool calls, file operations, or browser actions
- Latency β adds ~100-400ms per message (same-region); fail-open prevents blocking on timeout
- Not a complete security solution β complements (doesn't replace) OpenClaw's built-in approval system
- Verify env vars are set in the gateway process (not just your shell)
- On K8s: check that hooks config is in the ConfigMap (see K8s section)
- Check gateway logs:
kubectl logs <pod> | grep -i "hook\|armor"
Set both required environment variables and restart the gateway.
- SA key auth: Verify the SA has
roles/modelarmor.useron the project - gcloud auth: Run
gcloud auth loginand ensure proper permissions - Domain delegation: Verify the SA has domain-wide delegation configured in Google Workspace Admin
The template doesn't exist in the specified region. Templates are regional β make sure MODEL_ARMOR_LOCATION matches where you created it.
Model Armor adds per-request latency (~100-400ms). Use inspect mode to avoid blocking the message pipeline.
Contributions are welcome! Please open an issue or submit a PR.