Add a Header Workflow
In this tutorial, we will create a passive workflow that will add a header to an in-scope request and resend the request with it.
Creating a Passive Workflow
To begin, navigate to the Workflows interface, select the Passive tab, and click the + New workflow button.

Next, rename the workflow by typing in the Name input field. You can also provide an optional description of the workflow's functionality by typing in the Description input field.
Nodes and Connections
Too add nodes to the workflow, click on + Add Node button and then the + Add button of a specific node.
For this workflow, the overall node layout will be:

TIP
Passive workflows do not require Passive End nodes in order to exit execution properly.
- The
On Intercept Requestnode outputs$on_intercept_request.requestobjects which represent proxied requests. - The
In Scopenode checks if the value of a request's Host header is included in the in-scope list of a scope preset. If it is not - the workflow will end. - In-scope requests will be passed to the
Javascriptnode. - Once a request has been processed by the script in the
Javascriptnode, the workflow will end.
Adding a Header to a Request
Click on the
Javascriptnode to access its editor.Then, click within the coding environment, select all of the existing code, and replace it with the following script:
/**
* @param {HttpInput} input
* @param {SDK} sdk
* @returns {MaybePromise<Data | undefined>}
*/
export async function run({ request, response }, sdk) {
if (request) {
const spec = request.toSpec();
spec.setHeader("Header-Name", "header-value");
let resend = await sdk.requests.send(spec);
if (resend.response) {
let finding = {
title: `Custom Header Passive Workflow.`,
description: `Request ${resend.request.getId()} ${resend.request.getMethod()} ${resend.request.getPath()} to ${resend.request.getHost()} was resent with custom header.`,
reporter: "Add Header & Resend Request",
request: resend.request
};
await sdk.findings.create(finding);
}
}
}- Next, ensure the
$on_intercept_request.requestobject is referenced as input data.

Once these steps are completed, close the editor window and click on the Save button to update and save the configuration.
Script Breakdown
First, an asynchronous function is defined that takes a proxied request and response object pair and the sdk interface object as parameters. The script will execute every time an in-scope request object is passed from the In Scope node.
export async function run({ request, response }, sdk) {
if (request) {As request objects are initially immutable, the .toSpec() method is used to make a copy of the request object so modifications can be made. The mutable request is stored in the spec variable.
const spec = request.toSpec();Next, the .setHeader("Header-Name", "header-value") method is used to add a header to the copy of the request object.
spec.setHeader("Header-Name", "header-value");Then, sdk.requests.send(spec) is used to send the modified request.
Since we must wait for the request to be sent and response to be returned, the await directive is used.
The request and its corresponding response are stored in the resend variable.
let resend = await sdk.requests.send(spec);If a response is returned, a finding object is created. The request property is the request that includes our custom header.
if (resend.response) {
let finding = {
title: `Custom Header Passive Workflow.`,
description: `Request ${resend.request.getId()} ${resend.request.getMethod()} ${resend.request.getPath()} to ${resend.request.getHost()} was resent with custom header.`,
reporter: "Add Header & Resend Request",
request: resend.request
};Finally, the creation of the finding is awaited to give it time to be processed on the backend.
await sdk.findings.create(finding);
}
}
}Testing the Workflow
To test the workflow:
Type in an in-scope domain in the connection URL input field.
Ensure the domain is also the value of the request's Host header.
- Next, click on the
Runbutton. A message will appear notifying you that the workflow executed successfully.

The Result
The generated finding should resemble:

The full workflow is provided below, ready to be imported.
Full workflow
{
"description": "Adds a header to a proxied request.",
"edition": 2,
"graph": {
"edges": [
{
"source": {
"exec_alias": "exec",
"node_id": 0
},
"target": {
"exec_alias": "exec",
"node_id": 2
}
},
{
"source": {
"exec_alias": "true",
"node_id": 2
},
"target": {
"exec_alias": "exec",
"node_id": 3
}
},
{
"source": {
"exec_alias": "false",
"node_id": 2
},
"target": {
"exec_alias": "exec",
"node_id": 1
}
},
{
"source": {
"exec_alias": "exec",
"node_id": 3
},
"target": {
"exec_alias": "exec",
"node_id": 4
}
}
],
"nodes": [
{
"alias": "on_intercept_request",
"definition_id": "caido/on-intercept-request",
"display": {
"x": -210,
"y": -20
},
"id": 0,
"inputs": [],
"name": "On intercept request",
"version": "0.1.0"
},
{
"alias": "passive_end",
"definition_id": "caido/passive-end",
"display": {
"x": 210,
"y": 70
},
"id": 1,
"inputs": [],
"name": "Passive End",
"version": "0.1.0"
},
{
"alias": "in_scope",
"definition_id": "caido/in-scope",
"display": {
"x": 0,
"y": -10
},
"id": 2,
"inputs": [
{
"alias": "request",
"value": {
"data": "$on_intercept_request.request",
"kind": "ref"
}
}
],
"name": "In Scope",
"version": "0.1.0"
},
{
"alias": "javascript",
"definition_id": "caido/http-code-js",
"display": {
"x": 210,
"y": -90
},
"id": 3,
"inputs": [
{
"alias": "request",
"value": {
"data": "$on_intercept_request.request",
"kind": "ref"
}
},
{
"alias": "code",
"value": {
"data": "/**\n * @param {HttpInput} input\n * @param {SDK} sdk\n * @returns {MaybePromise<Data | undefined>}\n */\nexport async function run({ request, response }, sdk) {\n if (request) { \n const spec = request.toSpec();\n spec.setHeader(\"Header-Name\", \"header-value\");\n\n let resend = await sdk.requests.send(spec);\n \n if (resend.response) {\n let finding = {\n title: `Custom Header Passive Workflow.`,\n description: `Request ${resend.request.getId()} ${resend.request.getMethod()} ${resend.request.getPath()} to ${resend.request.getHost()} was resent with custom header.`,\n reporter: \"Add Header & Resend Request\",\n request: resend.request\n };\n await sdk.findings.create(finding);\n }\n }\n}",
"kind": "string"
}
}
],
"name": "Javascript",
"version": "0.1.0"
},
{
"alias": "passive_end_1",
"definition_id": "caido/passive-end",
"display": {
"x": 420,
"y": -90
},
"id": 4,
"inputs": [],
"name": "Passive End 1",
"version": "0.1.0"
}
]
},
"id": "eb670e67-9752-4324-9fb8-1aa529e7e9da",
"kind": "passive",
"name": "Add Header"
}