hemlock defend monitor¶
In-band detection middleware. Listens on --listen and reverse-proxies all traffic to --upstream. For every JSON response that includes a response string field, runs the embedded strict-canary detector and:
- Sets
X-Hemlock-Detection: high|medium|low|noneon the response - Sets
X-Hemlock-Specific-Hits: ...when canary substrings matched - Inserts a
_hemlockverdict block into the response JSON (use--annotate=falseto keep responses byte-identical) - Appends an audit row to
--audit-logif set - Replaces high/medium responses with
403 Forbidden+ JSON refusal when--block-on-detectis passed
Defaults are non-intrusive: the proxy only annotates. Operators that want enforcement opt in via --block-on-detect.
Synopsis¶
Flags¶
| Flag | Type | Default | Description |
|---|---|---|---|
--upstream |
string |
(required) | URL of the protected pipe (e.g. http://localhost:8100) |
--listen |
string |
:8200 |
Bind address for the proxy |
--canary-version |
string |
v1 |
Canary registry version used by the embedded detector |
--payload-category |
string |
(merged) | Indicator-list category (default merges across all categories) |
--audit-log |
string |
JSONL audit log path (default: no audit log) | |
--block-on-detect |
bool |
false |
Replace high/medium responses with 403 + refusal |
--annotate |
bool |
true |
Insert _hemlock verdict block into response JSON |
--quiet |
bool |
false |
Suppress per-request stderr logs |
Admin endpoints¶
The proxy serves two endpoints itself (not forwarded to the upstream):
| Path | Purpose |
|---|---|
GET /__hemlock/health |
Reports upstream + registry pin + block-on-detect setting |
GET /__hemlock/stats |
Lifetime counters: requests, detected, high, blocked |
Audit log shape¶
When --audit-log is set, one JSON object per request is appended:
{
"ts": "2026-05-06T01:27:09.076569Z",
"path": "/query",
"method": "POST",
"detection": "high",
"detected": true,
"specific_hits": ["HEMLOCK_INJECTION_TEST"],
"generic_hits": null,
"payload_echoed": false,
"response_excerpt": "The answer is HEMLOCK_INJECTION_TEST."
}
Examples¶
Front the local LangChain pipe with annotation only (default), audit log on:
hemlock defend monitor \
--upstream http://localhost:8100 \
--listen :8200 \
--audit-log ./monitor-audit.jsonl
Now query the proxy instead of the pipe directly:
curl -sS -X POST -D - \
--data-urlencode "q=What is the answer?" \
--data-urlencode "collection=hemlock_smoke" \
http://127.0.0.1:8200/query
Headers reveal the detector verdict:
HTTP/1.1 200 OK
Content-Type: application/json
X-Hemlock-Detection: high
X-Hemlock-Specific-Hits: HEMLOCK_INJECTION_TEST
X-Hemlock-Version: dev
Block high/medium-confidence injections instead of just flagging them:
Blocked responses come back as 403 Forbidden with a JSON refusal carrying the verdict:
{ "error": "blocked by hemlock defend monitor", "reason": "injection detected in upstream response", "_hemlock": { ... } }
Related¶
hemlock defend detect— the underlying strict-canary detector, used in batch mode against collected response sampleshemlock defend report— render the audit log into an operator briefhemlock stack— bring up the four-pipe target the monitor fronts