api-relay-audit
toby-bridges
Local security audit for AI API relays and LLM proxies: detects prompt injection, model substitution, tool-call rewriting, SSE anomalies, error leakage, and Web3 wallet risks.
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:guhanfei-ai/dsh-human-intent
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
Human intent verification and cryptographic action authorization for AI agents.
AI can propose an action. Only a human can authorize it.
Agent proposes Action
↓
Canonicalize Action
↓
Hash Exact Intent
↓
Human sees exact Action
↓
Human verifies (WebAuthn: Touch ID / Windows Hello / passkey)
↓
Cryptographically sign Intent
↓
Generate Intent Receipt
↓
Verify exact Action binding
↓
Execute
AI agents can increasingly execute real-world actions: delete data, deploy services, spend money, send messages. An agent having the capability to run a tool does not mean a human granted the authority to run it.
Capability != Authority.
Existing human-in-the-loop mechanisms usually verify a fuzzy fact — "a human
touched the sensor" — and then hand the agent a blanket verified = true,
often valid for a window of time. Nothing binds the approval to the exact
action. An approval obtained for rm -rf ./test-data silently authorizes
rm -rf ./production-data.
dsh-human-intent closes that gap. Every authorization is:
This project is not a fingerprint-identification system and does not identify a specific natural person. WebAuthn platform authenticators (Touch ID / Windows Hello / passkeys) prove that the holder of a registered credential performed a user-verification gesture. That proof is what gets bound to the action. See Security Model.
tools/pre-execute policy hook) proposes an
IntentRequest: tool, operation, target, arguments, risk, reason.intentHash = SHA-256(canonical intent).Requirements: Node.js ≥ 20.11.
npm install
npm run verify # build + lint + tests + http smoke test
npm run demo # interactive acceptance scenarios A–E
Demo walkthrough (the part you show people):
npm run demo
Run the approval server standalone:
npm run serve # http://localhost:8787
node bin/dsh-human-intent.js serve --port 9000 --data-dir ./data
Inspect a receipt (validates structure, integrity and signature):
node bin/dsh-human-intent.js inspect receipt.json
Read the audit log:
node bin/dsh-human-intent.js audit
Inside DeepSeek Harness (DSH), the plugin provides:
human_intent_request — propose an action, wait for the human, receive
an IntentReceipt (or an explicit denial).human_intent_verify — verify a receipt authorizes one exact action
before executing it.human_intent_status — enforcement status.tools/pre-execute policy enforcement for protectedTools./human-intent/api.{
"protectedTools": ["shell.exec", "kubectl.*"],
"rules": [{ "tool": "shell.exec", "risk": "high" }]
}
Glob semantics: shell.* matches one dot-segment (shell.exec, not
shell.exec.sub); shell.** spans segments. Exact names always work.
Local development:
npm install
npm run build:client
dsh plugin --profile web add link:/Users/you/dsh-human-intent
The DSH client UI must be served from
localhostfor WebAuthn to be available, and the DSH host origin must be listed inallowedOrigins.
| Option | Default | Meaning |
|---|---|---|
enabled |
true |
Enforce human intent for protected tools. |
protectedTools |
[] |
Tool names / dot-globs requiring authorization. |
rules |
[] |
{ tool, risk } rules combining protection and risk level. |
rpID |
localhost |
WebAuthn relying-party ID. |
allowedOrigins |
http://localhost:<port> |
WebAuthn origin allowlist. |
requestTtlMs |
120000 |
Human decision window. |
dataDir |
(memory) | Directory for credentials.json + audit.jsonl. |
interface IntentRequest {
version: "0.1"
requestId: string // unique per request
intentHash: string // SHA-256 over the canonical intent
nonce: string // 256-bit unguessable, one per request
action: {
tool: string // e.g. "shell.exec"
operation?: string
target?: string // e.g. "namespace/prod/pod/foo"
arguments: object // exact arguments
}
context?: {
description?: string
reason?: string
risk?: "low" | "medium" | "high" | "critical"
}
agent?: { id?: string; name?: string }
session?: { id?: string }
issuedAt: string // ISO 8601
expiresAt: string // ISO 8601
}
interface IntentReceipt {
kind: "IntentReceipt"
version: "0.1"
requestId: string
intentHash: string // the action this receipt authorizes
decision: "approved" | "denied"
intent: IntentRequest // embedded, integrity-checked
authenticator: { type: "webauthn"; credentialId: string }
verification: { method: "webauthn"; userVerified: boolean }
signedAt: string
expiresAt: string // same window as the request
nonce: string
assertion?: { /* raw WebAuthn assertion for re-verification */ }
deniedReason?: string
}
Receipts serialize, verify and audit (docs/PROTOCOL.md).
What this project guarantees, precisely:
tool=A, args=X produces a receipt that
cannot authorize tool=A, args=Y or tool=B, args=X. The intentHash
covers tool, operation, target, arguments, nonce, requestId and the
validity window.@simplewebauthn/server. No client-provided
verified: true is ever trusted.What this project does not claim:
Agent
↓ IntentRequest
Canonicalizer (RFC 8785 JCS)
↓ CanonicalIntent
Hasher (SHA-256)
↓ IntentHash
Human Intent UI (exact action, risk, arguments, expiry)
↓ WebAuthn ceremony (challenge = intentHash)
Verifier (@simplewebauthn/server: origin, RP, key, signature, counter, UV)
↓ IntentReceipt
Policy / Consumption Gate (action re-hash, one-shot, expiry)
↓
Tool Execution (exactly the authorized action)
Details: docs/ARCHITECTURE.md · Protocol: docs/PROTOCOL.md · Threats: docs/THREAT_MODEL.md
npm run demo runs the five acceptance scenarios:
| Scenario | Demonstrates |
|---|---|
| A | Destructive command → human approves → exact action executes once. |
| B | Human approves ./test-data; agent swaps to ./production-data → rejected (action_mismatch). |
| C | Approved receipt replayed a second time → rejected (already_consumed). |
| D | Request window elapses → expired, nothing executes. |
| E | Human presses Deny → agent receives an explicit denied decision. |
dsh-human-intent evolved from dsh-fingerprint-signature, which gated protected tools behind a platform user-verification popup and granted a 30-second blanket pass. That design verified human presence but nothing about which action the human was approving.
This project keeps the plugin structure and the loopback-API pattern that worked there, and replaces the security model:
| dsh-fingerprint-signature | dsh-human-intent | |
|---|---|---|
| Verified fact | "a human is present" | "a human authorized this exact action" |
| Binding | none (blanket grant) | intentHash (tool + target + arguments) |
| Proof | helper exit code | WebAuthn signature (server-verified) |
| Validity | 30s window | one-shot, request-window-bounded |
| Denial | timeout only | explicit denied receipt |
| Audit | none | append-only audit log |
The signature-variable feature (names, identity IDs, custom variables injected into the agent context) is not migrated: it is a different use case. Keep using dsh-fingerprint-signature for it; both plugins can be installed side by side.
See docs/MIGRATION.md.
localhost-served UI and a
WebAuthn-capable browser.MIT — see LICENSE.
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: agent-security、security。