Skip to content
Skillv1.0.0

openhunt-caido-workflows

Reference for all OpenHunt passive Caido detection workflows — their IDs, categories, detection logic, SDK patterns, dedup strategies, and file structure. Use when creating new Caido workflows or buil

by razor-ai(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from razor-ai/openhunt (openhunt/caido/custom-workflows/SKILL.md). Install upstream with npx skills add razor-ai/openhunt --skill custom-workflows. Copyright stays with the author.

OpenHunt Caido Custom Workflows

Overview

This directory contains 97 passive Caido workflows that form a detection net for the OpenHunt security testing pipeline. All workflows run as passive intercept handlers — they observe proxied traffic and create findings (signals, not confirmed vulnerabilities) via the Caido SDK.

Every workflow writes findings with reporter: "openhunt-detect" and uses deduplication keys to avoid flooding the findings tab with repeats.

Directory Structure

caido/custom-workflows/
├── SKILL.md                                    # This file
├── README.md                                   # Workflow summary table
│
├── hunt-admin-interface-detector/              # Access Control
│   ├── definition.json
│   ├── javascript.ts
│   ├── manifest.json
│   └── README.md
├── hunt-business-logic-surface/                # Access Control
│   ├── definition.json
│   ├── javascript.ts
│   ├── manifest.json
│   └── README.md
├── hunt-idor-surface-mapper/                   # Access Control
│   ├── definition.json
│   ├── javascript.ts
│   ├── manifest.json
│   └── README.md
├── hunt-mass-assignment-indicator/             # Access Control
│   ├── definition.json
│   ├── javascript.ts
│   ├── manifest.json
│   └── README.md
├── hunt-race-condition-surface/                # Access Control
│   ├── definition.json
│   ├── javascript.ts
│   ├── manifest.json
│   └── README.md
├── hunt-rate-limit-absence/                    # Access Control
│   ├── definition.json
│   ├── javascript.ts
│   ├── manifest.json
│   └── README.md
│
├── hunt-auto-auth-renewal/                     # Session Management (request-trigger)
│   ├── definition.json
│   ├── javascript.ts
│   ├── manifest.json
│   └── README.md
│
├── hunt-account-takeover-surface/              # Authentication
├── hunt-cryptographic-exploitation-surface/    # Authentication
├── hunt-jwt-weakness-analyzer/                 # Authentication
├── hunt-mfa-otp-surface-mapper/                # Authentication
├── hunt-oauth-oidc-surface-mapper/             # Authentication
├── hunt-saml-response-analyzer/                # Authentication
├── hunt-session-cookie-analyzer/               # Authentication / Session Management
├── hunt-type-juggling-surface/                 # Authentication
├── hunt-auth-token-in-url/                     # Authentication / Information Disclosure
│
├── hunt-cache-poisoning-surface/               # Caching & Proxies
├── hunt-reverse-proxy-misconfig/               # Caching & Proxies
├── hunt-web-cache-deception-surface/           # Caching & Proxies
│
├── hunt-cloud-resource-exposure/               # Cloud & Infrastructure
├── hunt-google-api-attack-surface/             # Cloud & Infrastructure
├── hunt-google-discovery-surface/              # Cloud & Infrastructure
├── hunt-graphql-attack-surface/                # Cloud & Infrastructure
├── hunt-subdomain-takeover/                    # Cloud & Infrastructure
├── hunt-websocket-attack-surface/              # Cloud & Infrastructure
│
├── hunt-client-side-path-traversal/            # File Handling
├── hunt-file-upload-detector/                  # File Handling
├── hunt-lfi-response-patterns/                 # File Handling
├── hunt-path-traversal-indicators/             # File Handling
├── hunt-zip-slip-surface/                      # File Handling
│
├── hunt-cookie-scope-creep/                    # Headers & Security Configuration
├── hunt-hsts-bypass-detector/                  # Headers & Security Configuration
├── hunt-security-headers/                      # Headers & Security Configuration
│
├── hunt-http2-connection-surface/              # Infrastructure (Derived)
│
├── hunt-api-key-detector/                      # Information Disclosure
├── hunt-error-debug-leak/                      # Information Disclosure
├── hunt-google-protojson-error-oracle/         # Information Disclosure
├── hunt-internal-leak-detector/                # Information Disclosure
├── hunt-password-credential-response/          # Information Disclosure
├── hunt-scm-disclosure/                        # Information Disclosure
├── hunt-sensitive-data-sniffer/                # Information Disclosure
├── hunt-stack-trace-detector/                  # Information Disclosure
├── hunt-tech-fingerprint/                      # Information Disclosure
│
├── hunt-command-injection-indicators/          # Injection
├── hunt-crlf-injection-surface/                # Injection
├── hunt-deserialization-surface/               # Injection
├── hunt-email-injection-surface/               # Injection
├── hunt-graphql-introspection-detector/        # Injection
├── hunt-ldap-injection-indicators/             # Injection
├── hunt-nosql-injection-surface/               # Injection
├── hunt-sql-error-detector/                    # Injection
├── hunt-ssi-esi-indicators/                    # Injection
├── hunt-ssti-indicator/                        # Injection
├── hunt-xxe-xml-processing-surface/            # Injection
├── hunt-csv-formula-injection/                 # Injection (Derived)
├── hunt-latex-injection-surface/               # Injection (Derived)
├── hunt-lucene-solr-injection/                 # Injection (Derived)
├── hunt-xpath-injection-indicators/            # Injection (Derived)
├── hunt-xslt-processing-surface/              # Injection (Derived)
│
├── hunt-debug-mode-indicator/                  # Miscellaneous High-Value
├── hunt-insecure-randomness/                   # Miscellaneous High-Value
├── hunt-response-code-patterns/                # Miscellaneous High-Value
├── hunt-timing-attack-surface/                 # Miscellaneous High-Value
├── hunt-webhook-integration/                   # Miscellaneous High-Value
│
├── hunt-cors-misconfiguration/                 # SSRF & Request Manipulation
├── hunt-csrf-surface-mapper/                   # SSRF & Request Manipulation
├── hunt-hidden-parameter-surface/              # Request Manipulation
├── hunt-host-header-poisoning/                 # SSRF & Request Manipulation
├── hunt-hpp-surface/                           # SSRF & Request Manipulation
├── hunt-open-redirect-collector/               # SSRF & Request Manipulation
├── hunt-request-smuggling-indicators/          # SSRF & Request Manipulation
├── hunt-ssrf-parameter-mapper/                 # SSRF & Request Manipulation
├── hunt-sspp-surface/                          # Request Manipulation (Derived)
├── hunt-verb-tampering-surface/                # Request Manipulation (Derived)
│
├── hunt-clickjacking-surface/                  # XSS & Client-Side
├── hunt-client-cve-surface/                    # XSS & Client-Side
├── hunt-cross-site-leak-surface/               # XSS & Client-Side
├── hunt-csp-analyzer/                          # XSS & Client-Side
├── hunt-css-injection-surface/                 # XSS & Client-Side
├── hunt-dom-clobbering-surface/                # XSS & Client-Side
├── hunt-dom-sink-collector/                    # XSS & Client-Side
├── hunt-electron-exploitation-surface/         # XSS & Client-Side
├── hunt-postmessage-handler/                   # XSS & Client-Side
├── hunt-prototype-pollution/                   # XSS & Client-Side
├── hunt-reflected-params/                      # XSS & Client-Side
├── hunt-spa-state-manipulation/                # XSS & Client-Side
├── hunt-tabnabbing-surface/                    # XSS & Client-Side
│
├── hunt-dns-rebinding-surface/                 # Server-Side Request
└── hunt-headless-browser-surface/              # Server-Side Request

Each workflow folder contains exactly 4 files:

File Purpose
definition.json Caido workflow graph: trigger node → in-scope filter → HTTPQL pre-filter → JavaScript node → end. Contains the JS code inline in the code input.
javascript.ts Standalone copy of the detection logic (same code as embedded in definition.json). This is the source of truth for editing.
manifest.json Workflow metadata: id (slug), name, version, author, description, url.
README.md Human-readable docs: what it detects, detection criteria, signal output format, false positive rate, next steps, community overlap.

Workflow Architecture

Trigger Types

  • 88 workflows use on-intercept-response — they analyze responses after they arrive from the server.
  • 1 workflow (hunt-auto-auth-renewal) uses on-intercept-request — it modifies outgoing requests to inject fresh auth tokens.

Standard Graph Structure (definition.json)

All passive workflows share a 5-node graph with an HTTPQL pre-filter:

Node 2: Trigger (on-intercept-response or on-intercept-request)
  │
  ▼
Node 3: In Scope filter
  │
  ├─ false → Node 1: Passive End (skip)
  │
  └─ true  → Node 5: Matches HTTPQL (pre-filter)
                │
                ├─ false → Node 1: Passive End (skip)
                │
                └─ true  → Node 4: JavaScript (detection logic)
                              │
                              └─→ Node 1: Passive End

The exception is hunt-auto-auth-renewal, which is a utility workflow with no HTTPQL node and uses the older 4-node structure.

The definition.json encodes this as:

  • kind: always "passive"
  • edition: always 2
  • id: a UUID (unique per workflow)
  • graph.nodes[2]: trigger — definition_id: "caido/on-intercept-response" (or "caido/on-intercept-request")
  • graph.nodes[3]: scope check — definition_id: "caido/in-scope", input refs the trigger's request
  • graph.nodes[5]: HTTPQL filter — definition_id: "caido/matches-httpql", pre-filters traffic before JS execution
  • graph.nodes[4]: JS node — definition_id: "caido/http-code-js", inputs ref trigger's request and response

manifest.json Format

{
  "author": { "name": "OpenHunt" },
  "url": "https://github.com/larsencyber/openhunt",
  "description": "<one-line description>",
  "id": "hunt-<workflow-slug>",
  "name": "<Human Readable Name>",
  "version": "1.0.0"
}

Caido Workflow SDK API

All workflows use the same function signature:

export async function run({ request, response }, sdk) { ... }

Request Object

Method Returns Notes
request.getHost() string Hostname without port
request.getPort() number
request.getPath() string URL path without query string
request.getMethod() string HTTP method
request.getQuery() string | undefined Query string without leading ?
request.getHeaders() Record<string, string[]> All headers, keys lowercased
request.getHeader(name) string[] Single header values
request.getBody() { toText(): string, length: number } | undefined Request body
request.getTls() boolean Whether HTTPS
request.getUrl() string Full URL
request.getId() string Request ID
request.setHeader(name, value) void Mutate outgoing request (request-trigger only)
request.removeHeader(name) void Remove header (request-trigger only)

Response Object

Method Returns Notes
response.getCode() number HTTP status code
response.getHeaders() Record<string, string[]> All headers, keys lowercased
response.getHeader(name) string[] Single header values
response.getBody() { toText(): string, length: number } | undefined Response body
response.getRoundtripTime() number Round-trip time in ms

SDK Findings API

// Check if a finding with this dedup key already exists
const exists = await sdk.findings.exists({ dedupeKey: string });

// Create a new finding
await sdk.findings.create({
  title: string,          // Short descriptive title
  description: string,    // Detailed finding description
  reporter: string,       // Always "openhunt-detect" for these workflows
  request: RequestObject, // The request object from run()
  dedupeKey: string,      // Unique key for deduplication
});

SDK Console API

sdk.console.log(msg);    // Log to Caido console
sdk.console.debug(msg);
sdk.console.warn(msg);
sdk.console.error(msg);

SDK Environment API

sdk.env.getVar(name);      // Get environment variable
sdk.env.getVars();         // Get all variables as [{name, value}]
await sdk.env.setVar({ name, value }); // Set variable

Common Patterns in Detection Code

1. Standard Guards (use in every response-trigger workflow)

export async function run({ request, response }, sdk) {
  if (!response) return;

  // Skip oversized responses (>500KB)
  if ((response.getBody()?.length ?? 0) > 500000) return;

  // Skip binary content types
  const respHeaders = response.getHeaders();
  const contentType = (respHeaders['content-type']?.[0] ?? '').toLowerCase();
  const binaryTypes = ['image/', 'font/', 'audio/', 'video/',
    'application/octet-stream', 'application/zip', 'application/pdf'];
  if (binaryTypes.some(t => contentType.includes(t))) return;

  const host = request.getHost();
  const path = request.getPath();
  const respBody = response.getBody()?.toText() ?? '';
  // ... detection logic ...
}

2. Findings with Deduplication

Every workflow builds a deduplication key from a prefix + contextual data to avoid repeat findings:

// Per host + path dedup (most common — 60+ workflows)
const dedupeKey = `detect:hunt-<id>:${host}:${path}`;

// Per host only (e.g., CORS, HSTS, tech fingerprint)
const dedupeKey = `detect:hunt-<id>:${host}`;

// Per host + path + slug (for multi-detection workflows)
const slug = f.title.replace(/[^a-zA-Z0-9]/g, '').substring(0, 40);
const dedupeKey = `detect:hunt-<id>:${host}:${path}:${slug}`;

// Per host + param name (e.g., SSRF mapper)
const dedupeKey = `detect:hunt-<id>:${host}:${paramName}`;

// Per host + method + path (e.g., CSRF, mass assignment)
const dedupeKey = `detect:hunt-<id>:${host}:${method}:${path}`;

// Per host + cookie name (e.g., session cookie analyzer)
const dedupeKey = `detect:hunt-<id>:${host}:${cookieName}`;

// Always check before creating:
const exists = await sdk.findings.exists({ dedupeKey });
if (exists) continue;

3. Finding Description Format

All findings follow a consistent structure:

await sdk.findings.create({
  title: `DETECT: <What Was Found>`,
  description: [
    `Host: ${host}`,
    `Path: ${path}`,
    `Confidence: High|Medium|Low`,
    `<Detailed explanation of what was detected>`,
    `Next step: <Actionable guidance for the tester>`,
    `Skill: ~/.claude/skills/<path-to-relevant-skill>/`,
  ].join('\n'),
  reporter: 'openhunt-detect',
  request,
  dedupeKey,
});

4. Multi-Finding Pattern

Workflows that detect multiple things in one pass collect findings in an array, then create them:

const findings = [];

// Detection 1
if (condition1) {
  findings.push({ title: '...', detail: '...', confidence: 'High' });
}

// Detection 2
if (condition2) {
  findings.push({ title: '...', detail: '...', confidence: 'Medium' });
}

// Create all findings with dedup
for (const f of findings) {
  const slug = f.title.replace(/[^a-zA-Z0-9]/g, '').substring(0, 40);
  const dedupeKey = `detect:hunt-<id>:${host}:${path}:${slug}`;
  const exists = await sdk.findings.exists({ dedupeKey });
  if (exists) continue;
  await sdk.findings.create({ title: f.title, description: '...', reporter: 'openhunt-detect', request, dedupeKey });
}

5. Scanning Request Parameters (query + body)

Used by SSRF mapper, reflected params, HPP, and others:

// Query string
const query = request.getQuery() ?? '';
const params = new URLSearchParams(query);
for (const [name, value] of params.entries()) {
  checkParam(name, value, 'query');
}

// POST body (form-urlencoded)
if (contentType.includes('application/x-www-form-urlencoded')) {
  const bodyText = request.getBody()?.toText() ?? '';
  const bodyParams = new URLSearchParams(bodyText);
  for (const [name, value] of bodyParams) {
    checkParam(name, value, 'body.form');
  }
}

// POST body (JSON) — recursive scan
if (contentType.includes('application/json')) {
  const json = JSON.parse(request.getBody()?.toText() ?? '{}');
  const scanObj = (obj, prefix) => {
    for (const [key, val] of Object.entries(obj)) {
      if (typeof val === 'string') checkParam(key, val, `body.json${prefix ? '.' + prefix : ''}`);
      else if (typeof val === 'object' && val !== null && !Array.isArray(val))
        scanObj(val, prefix ? prefix + '.' + key : key);
    }
  };
  scanObj(json, '');
}

6. HTML Title Extraction

const titleMatch = respBody.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
if (titleMatch) {
  const title = titleMatch[1].trim().toLowerCase();
  // ... check against keyword lists
}

7. Header Comment Block

Every javascript.ts starts with a standard metadata comment:

/**
 * OpenHunt Detection: <Human Name>
 * ID: hunt-<slug>
 * Category: <Category>
 * Colour: <hex>
 * Dedup: <strategy>
 * Skill refs: skills/<path>/
 * Community overlap: <description>
 */

Workflow Categories

Category Count Colour Description
Access Control 6 #f97316 / #3b82f6 / #f59e0b Admin interfaces, business logic, IDOR, mass assignment, race conditions, rate limiting
Authentication 9 #a855f7 Account takeover, cryptographic exploitation, JWT, MFA/OTP, OAuth/OIDC, SAML, session cookies, type juggling, auth tokens in URLs
Session Management 1 #22c55e Auto auth token renewal
Caching & Proxies 3 #f59e0b Cache poisoning, reverse proxy misconfig, web cache deception
Cloud & Infrastructure 6 #3b82f6 / #ef4444 Cloud resources, GraphQL, Google API attack surface + discovery, subdomain takeover, WebSocket
File Handling 5 #ef4444 / #3b82f6 Client-side path traversal, file upload, LFI, path traversal, zip slip
Headers & Security 3 #a855f7 / #6b7280 Cookie scope, HSTS bypass, security headers
Infrastructure 1 #3b82f6 HTTP/2 connection surface
Information Disclosure 9 #ef4444 / #f97316 / #22c55e API keys, error leaks, Google ProtoJSON schema leakage, internal IPs, passwords, SCM, sensitive data, stack traces, tech fingerprinting
Injection 16 Mixed SQL, NoSQL, command, email, LDAP, SSTI, SSI/ESI, XXE, XPath, XSLT, CSV formula, LaTeX, Lucene/Solr, deserialization, CRLF, GraphQL introspection
Miscellaneous 5 Mixed Debug mode, insecure randomness, response codes, timing attacks, webhooks
SSRF & Request Manipulation 10 #f59e0b / #f97316 / #6b7280 CORS, CSRF, hidden parameters, host header poisoning, HPP, open redirect, request smuggling, SSRF, SSPP, verb tampering
XSS & Client-Side 13 Mixed Clickjacking, client CVEs, cross-site leaks, CSP, CSS injection, DOM clobbering, DOM sinks, Electron exploitation, postMessage, prototype pollution, reflected params, SPA state manipulation, tabnabbing
Server-Side Request 2 Mixed DNS rebinding, headless browser exploitation

Colour Semantics

Hex Meaning Usage
#ef4444 Red — Critical High-confidence detections (API keys, SQL errors, path traversal, XSS)
#f97316 Orange — Warning Medium-confidence or surface mapping (CRLF, SSTI, command injection)
#f59e0b Amber — Surface Attack surface identification (SSRF params, CSRF endpoints, cache poison)
#3b82f6 Blue — Informational Structural observations (file upload, GraphQL, IDOR patterns)
#a855f7 Purple — Auth/Session Authentication and session management related
#22c55e Green — Utility Helper workflows (tech fingerprint, auto auth renewal)
#6b7280 Grey — Low severity Missing headers, HPP, clickjacking

Dedup Strategy Reference

Strategy Key Format Used By
per-host-path detect:hunt-<id>:<host>:<path> Most workflows (default)
per-host detect:hunt-<id>:<host> CORS, HSTS, subdomain takeover, tech fingerprint, HTTP/2, request smuggling
per-host-path-slug detect:hunt-<id>:<host>:<path>:<slug> Multi-detection workflows (admin interface, JWT, security headers)
per-host-method-path detect:hunt-<id>:<host>:<method>:<path> CSRF, mass assignment
per-host + param name detect:hunt-<id>:<host>:<paramName> SSRF parameter mapper
per-host-cookieName detect:hunt-<id>:<host>:<cookieName> Session cookie analyzer

Creating a New Workflow

Step 1: Create the folder

mkdir caido/custom-workflows/hunt-<your-slug>/

Step 2: Write javascript.ts

Start from this template:

/**
 * OpenHunt Detection: <Your Detection Name>
 * ID: hunt-<your-slug>
 * Category: <Category>
 * Colour: <hex>
 * Dedup: <strategy>
 * Skill refs: skills/<relevant-skill-path>/
 * Community overlap: <description or "none">
 */
export async function run({ request, response }, sdk) {
  if (!response) return;

  if ((response.getBody()?.length ?? 0) > 500000) return;

  const respHeaders = response.getHeaders();
  const contentType = (respHeaders['content-type']?.[0] ?? '').toLowerCase();
  const binaryTypes = ['image/', 'font/', 'audio/', 'video/', 'application/octet-stream', 'application/zip', 'application/pdf'];
  if (binaryTypes.some(t => contentType.includes(t))) return;

  const host = request.getHost();
  const path = request.getPath();
  const code = response.getCode();
  const respBody = response.getBody()?.toText() ?? '';

  const findings = [];

  // --- Your detection logic here ---

  // --- Create findings ---
  for (const f of findings) {
    const dedupeKey = `detect:hunt-<your-slug>:${host}:${path}`;
    const exists = await sdk.findings.exists({ dedupeKey });
    if (exists) continue;

    await sdk.findings.create({
      title: f.title,
      description: `Host: ${host}\nPath: ${path}\nConfidence: ${f.confidence}\n${f.detail}\nNext step: <guidance>\nSkill: ~/.claude/skills/<path>/`,
      reporter: 'openhunt-detect',
      request,
      dedupeKey,
    });
  }
}

Step 3: Create definition.json

Use this template — replace <NAME>, <DESCRIPTION>, <UUID>, and paste the full JS code into the data field of the code input:

{
  "description": "<DESCRIPTION>",
  "edition": 2,
  "graph": {
    "edges": [
      { "source": { "exec_alias": "exec", "node_id": 2 }, "target": { "exec_alias": "exec", "node_id": 3 } },
      { "source": { "exec_alias": "false", "node_id": 3 }, "target": { "exec_alias": "exec", "node_id": 1 } },
      { "source": { "exec_alias": "true", "node_id": 3 }, "target": { "exec_alias": "exec", "node_id": 5 } },
      { "source": { "exec_alias": "false", "node_id": 5 }, "target": { "exec_alias": "exec", "node_id": 1 } },
      { "source": { "exec_alias": "true", "node_id": 5 }, "target": { "exec_alias": "exec", "node_id": 4 } },
      { "source": { "exec_alias": "exec", "node_id": 4 }, "target": { "exec_alias": "exec", "node_id": 1 } }
    ],
    "nodes": [
      { "alias": "passive_end", "definition_id": "caido/passive-end", "display": { "x": 0, "y": 370 }, "id": 1, "inputs": [], "name": "Passive End", "version": "0.1.0" },
      { "alias": "on_intercept_response", "definition_id": "caido/on-intercept-response", "display": { "x": 0, "y": 10 }, "id": 2, "inputs": [], "name": "On Intercept Response", "version": "0.1.0" },
      { "alias": "in_scope", "definition_id": "caido/in-scope", "display": { "x": 0, "y": 85 }, "id": 3, "inputs": [ { "alias": "request", "value": { "data": "$on_intercept_response.request", "kind": "ref" } } ], "name": "In Scope", "version": "0.1.0" },
      { "alias": "javascript", "definition_id": "caido/http-code-js", "display": { "x": 0, "y": 245 }, "id": 4, "inputs": [ { "alias": "request", "value": { "data": "$on_intercept_response.request", "kind": "ref" } }, { "alias": "response", "value": { "data": "$on_intercept_response.response", "kind": "ref" } }, { "alias": "code", "value": { "data": "<PASTE FULL JS CODE HERE — escaped for JSON>", "kind": "string" } } ], "name": "<NAME>", "version": "0.1.0" },
      { "alias": "matches_httpql", "definition_id": "caido/matches-httpql", "display": { "x": 0, "y": 165 }, "id": 5, "inputs": [ { "alias": "request", "value": { "data": "$on_intercept_response.request", "kind": "ref" } }, { "alias": "response", "value": { "data": "$on_intercept_response.response", "kind": "ref" } }, { "alias": "query", "value": { "data": "<HTTPQL FILTER QUERY>", "kind": "string" } } ], "name": "Matches HTTPQL", "version": "0.1.0" }
    ]
  },
  "id": "<UUID>",
  "kind": "passive",
  "name": "<NAME>"
}

For request-trigger workflows (like auto-auth-renewal), change:

  • Node 2: definition_id: "caido/on-intercept-request", alias: "on_intercept_request"
  • Node 3 input ref: "$on_intercept_request.request"
  • Node 4 request input ref: "$on_intercept_request.request"
  • Node 4 response input: { "data": "", "kind": "string" } (empty — no response available)
  • Omit Node 5 (HTTPQL filter) — utility workflows use the 4-node structure

Step 4: Create manifest.json

{
  "author": { "name": "OpenHunt" },
  "url": "https://github.com/larsencyber/openhunt",
  "description": "<One-line description>",
  "id": "hunt-<your-slug>",
  "name": "<Human Readable Name>",
  "version": "1.0.0"
}

Step 5: Create README.md

# <Human Readable Name>

**ID:** `hunt-<your-slug>`
**Category:** <Category>
**Kind:** Passive
**Colour:** `<hex>`

## What it detects

<Description of what the workflow identifies>

## Detection criteria

- <Bullet list of specific conditions>

## Signal output

- **Title:** `DETECT: <pattern>`
- **Reporter:** `openhunt-detect`
- **Dedup:** `detect:hunt-<slug>:<host>:<path>`

## False positive rate

**Low|Medium|High** — <explanation>

## Next steps

<Actionable guidance>

## Community workflow overlap

**<name>** — <description> OR **none**

Testing Workflows

The test harness lives at caido/tests/ and uses the mock SDK:

# Run tests (from repo root)
node caido/tests/mock-harness.mjs caido/custom-workflows/hunt-<slug>/javascript.ts

# Static validation of all workflows
node caido/tests/static-validator.mjs

The mock SDK (caido/tests/mock-sdk.mjs) provides:

  • MockRequest — builder pattern: new MockRequest().host('example.com').path('/admin').build()
  • MockResponse — builder pattern: new MockResponse().status(200).header('content-type', 'text/html').body('<html>...').build()
  • MockSDK — tracks findings.created[] and findings.existsKeys for assertions

Naming Conventions

  • Folder name: hunt-<descriptive-slug> (all lowercase, hyphens)
  • Manifest ID: matches folder name exactly
  • Finding title prefix: always DETECT: followed by the detection name
  • Dedup key prefix: always detect:hunt-<short-id>: followed by scope components
  • Reporter: always openhunt-detect

Integration with Caido Plugins

Plugins that consume findings from these workflows should:

  1. Filter by reporter: Query findings where reporter === 'openhunt-detect'
  2. Parse finding titles: All titles start with DETECT: — the rest identifies the detection type
  3. Use dedup keys: The dedupeKey field uniquely identifies each finding instance
  4. Extract structured data from descriptions: Findings follow the format Host: ...\nPath: ...\nConfidence: ...\n<details>\nNext step: ...\nSkill: ...
  5. Reference the category table in the README.md to understand workflow groupings and colour semantics

Relationship to Other Skills

  • skills/caido-mode/ — CLI tool for interacting with Caido's API (search history, replay, findings, scopes)
  • skills/ — The security testing skills referenced in finding descriptions via Skill: lines

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/razor-ai-openhunt-custom-workflows/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

razor-ai-openhunt-custom-workflows.ocm.jsonjson
{
  "ocm": "1",
  "id": "razor-ai-openhunt-custom-workflows",
  "kind": "skill",
  "name": "openhunt-caido-workflows",
  "description": "Reference for all OpenHunt passive Caido detection workflows — their IDs, categories, detection logic, SDK patterns, dedup strategies, and file structure. Use when creating new Caido workflows or building plugins that consume findings from these detections.",
  "publisher": "razor-ai",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "general"
    ],
    "tags": [
      "skill-md",
      "worker",
      "caido",
      "detection",
      "workflows",
      "github"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Reference for all OpenHunt passive Caido detection workflows — their IDs, categories, detection logic, SDK patterns, dedup strategies, and file structure. Use when creating new Caido workflows or building plugins that consume findings from these detections."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "github",
      "repository": "https://github.com/razor-ai/openhunt",
      "path": "openhunt/caido/custom-workflows/SKILL.md",
      "ref": "5f7ebb2df6a505539f3baadb3cb2659ed0e1e8e0",
      "url": "https://github.com/razor-ai/openhunt/blob/5f7ebb2df6a505539f3baadb3cb2659ed0e1e8e0/openhunt/caido/custom-workflows/SKILL.md",
      "key": "razor-ai/openhunt/openhunt/caido/custom-workflows/SKILL.md"
    }
  },
  "instructions": "# OpenHunt Caido Custom Workflows\n\n## Overview\n\nThis directory contains 97 passive Caido workflows that form a detection net for the OpenHunt security testing pipeline. All workflows run as **passive intercept handlers** — they observe proxied traffic and create **findings** (signals, not confirmed vulnerabilities) via the Caido SDK.\n\nEvery workflow writes findings with `reporter: \"openhunt-detect\"` and uses deduplication keys to avoid flooding the findings tab with repeats.\n\n## Directory Structure\n\n```\ncaido/custom-workflows/\n├── SKILL.md                                    # This file\n├── REA",
  "cost": {
    "context_tokens": 7004
  }
}

Fetch it by URL: GET /api/v1/registry/razor-ai-openhunt-custom-workflows/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.