Back to skill

Security audit

HITL Protocol — Workflows and Human Decisions for Autonomous Agents

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent HITL protocol guide, but some examples can lead agents or services to trust externally supplied URLs with credentials or review data.

Treat this as Review rather than outright unsafe. Before installing or following it, ensure implementations validate all HITL URLs, bind poll/events/submit endpoints to trusted origins, never forward broad auth headers to arbitrary URLs, disable or revalidate redirects, block private and metadata network targets, and require callback registration or allowlisting before sending review results.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
references/agent-integration.md:62
Finding

Untrusted HITL Endpoints Can Receive Agent Authorization Headers

Content
View full analysis

Vulnerability Details

File Location: references/agent-integration.md:58-62, references/agent-integration.md:142-148, and SKILL.md:266
Vulnerability Type: Server-Side Request Forgery and credential disclosure through untrusted endpoint use
Risk Level: High

Complete Code Snippets

Polling implementation:

python
while True:
    time.sleep(30)
    poll_response = httpx.get(hitl["poll_url"], headers=auth_headers)

SSE implementation:

python
events_url = hitl.get("events_url")
if not events_url:
    return handle_hitl_polling(hitl, send_to_user, auth_headers)

try:
    with httpx_sse.connect(events_url, headers=auth_headers) as sse:

The root Skill also demonstrates the unsafe polling pattern:

python
poll = httpx.get(hitl["poll_url"], headers=auth).json()

Technical Analysis

The poll_url and events_url values originate in a remote service's HITL response. The examples issue requests to these URLs and attach caller-provided auth_headers without first establishing that the endpoint belongs to a trusted origin.

Although references/agent-integration.md:108-117 validates that review_url uses HTTPS and has a host, equivalent validation is not applied to poll_url or events_url. HTTPS alone would also be insufficient because an attacker can operate an HTTPS endpoint or provide a URL resolving to an internal address.

A malicious or compromised service can return an attacker-controlled endpoint and cause the agent to transmit reusable authorization headers to it. If internal and special-use destinations are reachable, the same behavior may also be used for server-side request forgery. Automatic redirects can bypass an initial validation check unless every redirect destination is independently checked.

Attack Path

  1. An agent sends a legitimate-looking request to a malicious or compromised service.
  2. The service returns HTTP 202 with a syntactic ...[truncated 1302 chars]
Remediation
View remediation

Remediation Suggestions

  1. Treat every endpoint in a remote HITL object as untrusted input.
  2. Require HTTPS for poll_url, events_url, and submit_url.
  3. Bind these endpoints to the origin of the API that produced the HITL response, or enforce a narrowly configured allowlist of trusted origins.
  4. Do not forward the original request's authorization headers to an arbitrary HITL URL. Use an endpoint-specific, audience-restricted, short-lived credential.
  5. Parse URLs strictly and reject embedded credentials, malformed hosts, unexpected ports, and ambiguous IP representations.
  6. Resolve hostnames and reject loopback, private, link-local, multicast, reserved, and cloud metadata destinations. Repeat validation after DNS resolution and immediately before connection.
  7. Disable redirects where possible. If redirects are necessary, validate every redirect hop and never forward sensitive authorization headers across origins.
  8. Apply outbound network controls so the agent process cannot reach unnecessary internal or metadata networks.
  9. Add request timeouts, response-size limits, and an explicit set of accepted content types.
  10. Update the example implementation to use a validated endpoint and scoped credentials before calling httpx.get or httpx_sse.connect.

T09 · Insecure Skill Coding Practices

Error
Location
references/service-integration.md:459
Finding

Unvalidated Callback URLs Permit SSRF and Review-Result Disclosure

Content
View full analysis

Vulnerability Details

File Location: references/service-integration.md:459-476
Vulnerability Type: Server-Side Request Forgery through attacker-supplied webhook destinations
Risk Level: High

Complete Code Snippet

markdown
## Callback/Webhook (Optional)

When the agent includes `hitl_callback_url` in the original request:

1. Echo it in `hitl.callback_url`
2. POST to the callback URL when the case reaches a terminal state
3. Sign with `X-HITL-Signature: sha256=<hmac>` (HMAC-SHA256 of request body)
4. Retry with exponential backoff (up to 3 attempts)

```json
POST {callback_url}
X-HITL-Signature: sha256=abc123...
Content-Type: application/json

{
  "event": "review.completed",
  "case_id": "review_abc123",
  "completed_at": "2026-02-22T10:15:00Z",
  "result": {
    "action": "select",
    "data": { "selected_jobs": ["job-123"] }
  }
}
text

### Technical Analysis

The guide directs a service to accept `hitl_callback_url` from an original request and later perform a server-side POST to that destination. It does not require destination allowlisting, HTTPS, callback ownership verification, private-address blocking, DNS rebinding protection, redirect validation, or registration authentication.

Signing the callback body protects integrity for a legitimate receiver, but it does not establish that the destination is safe. The service still makes an outbound request to a client-selected location and includes terminal review data in the request body.

Consequently, an attacker able to create a HITL case can potentially make the service connect to internal or special-use endpoints. If the callback points to an attacker-controlled host, terminal review results—including potentially sensitive `result.data`—are deliberately transmitted to that host.

### Attack Path

1. An attacker submits an API request that can create a HITL review case.
2. The request supplies `hitl_callback_url`
...[truncated 1231 chars]
Remediation
View remediation

Remediation Suggestions

  1. Authenticate and authorize clients before allowing callback registration.
  2. Require HTTPS callback URLs and reject URL-embedded credentials, fragments, malformed hosts, and unnecessary ports.
  3. Prefer pre-registered callback origins or a per-client allowlist rather than accepting arbitrary destinations for each request.
  4. Verify callback ownership during registration, such as through a challenge-response mechanism.
  5. Resolve callback hosts and reject loopback, private, link-local, multicast, reserved, and metadata addresses. Protect against DNS rebinding by validating the address used for the actual connection.
  6. Disable redirects, or validate every redirect hop without forwarding sensitive data to a different origin.
  7. Apply outbound firewall or proxy policy that blocks access to internal and special-use networks.
  8. Minimize callback payloads. Avoid including sensitive form values unless the registered receiver explicitly requires them and is authorized to receive them.
  9. Use unique, per-client signing secrets and document receiver-side constant-time signature verification.
  10. Add strict connection and response timeouts, response-size limits, retry caps, and audit logging that redacts secrets and sensitive review data.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (7)

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 106)May include surrounding context.

md
"spec_version": "0.7",
    "case_id": "review_abc123",
    "review_url": "https://service.example.com/review/abc123?token=K7xR2mN4pQ...",
    "poll_url": "https://api.service.example.com/v1/reviews/abc123/status",
    "type": "selection",
    "prompt": "Select which jobs to apply for",
    "timeout": "24h",

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 228)May include surrounding context.

md
spec_version: '0.6',
      case_id: caseId,
      review_url: `https://yourservice.com/review/${caseId}?token=${token}`,
      poll_url: `https://api.yourservice.com/v1/reviews/${caseId}/status`,
      type: 'selection',
      prompt: 'Select which jobs to apply for',
      timeout: '24h',

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 249)May include surrounding context.

python
import time, httpx

response = httpx.post("https://api.jobboard.com/search", json=query)

if response.status_code == 202:
    hitl = response.json()["hitl"]

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · SKILL.md (reported line 249)May include surrounding context.

python
import time, httpx

response = httpx.post("https://api.jobboard.com/search", json=query)

if response.status_code == 202:
    hitl = response.json()["hitl"]

Unbounded Resource Access

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill allows unbounded resource consumption (API calls, storage, compute). Without rate limits or quotas, a compromised or misbehaving agent can cause denial-of-service or cost overruns.

Content

Scanner excerpt · SKILL.md (reported line 416)May include surrounding context.

md
- Always share the primary result first
- Offer up to **2 improvement cycles** — one question per suggestion, re-submit with enriched data
- Stop when `improvement_suggestions` is empty or `maxAttempts` reached
- Never loop indefinitely

See [Agent Checklist — Quality Improvement Loop](agents/checklist.md#enhanced-quality-improvement-loop) and [Example 13](examples/13-quality-improvement-loop.json).

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/service-integration.md (reported line 495)May include surrounding context.

md
},
  "review_types": ["selection", "confirmation"],
  "review_base_url": "https://jobboard.example.com/review",
  "api_base_url": "https://api.jobboard.example.com/v1",
  "timeout_default": "24h",
  "features": {
    "callback": true,

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The document consistently presents this skill as HITL Protocol v0.7, including the manifest metadata and field descriptions, but the service quick-start example emits spec_version: '0.6'. This is an active documentation/code contradiction that could cause implementers to produce payloads inconsistent with the rest of the skill.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.