+
## Example
### X-Forwarded-For Passive Workflow
diff --git a/src/guides/automate.md b/src/guides/automate.md
index ad8beea..e3de931 100644
--- a/src/guides/automate.md
+++ b/src/guides/automate.md
@@ -28,6 +28,10 @@ To inspect the results of your `Automate` campaign - proceed with the following
4. This is the resulting list of options presented after right-clicking within the request pane.
5. The [HTTPQL query](/reference/httpql.md) input bar.
+
+
+
+
## Attack Strategies
Caido currently provides the following attack `Strategies`:
@@ -61,6 +65,10 @@ Preprocessors enable you to apply additional modifications to the payloads.
- **Prefix**: Allows you to prefix a payload value with a supplied value.
- **Suffix**: Allows you to append a supplied suffix value to a payload value.
+
+
+
+
Workflow Preprocessors are only available to Caido Pro users.
diff --git a/src/guides/filters.md b/src/guides/filters.md
index eb26250..bc01997 100644
--- a/src/guides/filters.md
+++ b/src/guides/filters.md
@@ -40,6 +40,10 @@ Currently, the tabs that support Scope selection are **HTTP History** and **Sear
2. In the `Advanced options` side menu that is presented - select/deselect the Filter Presets you want to apply.
3. As the example Filter Preset created is reliant on the presence of the **/about** path - you can confirm it is working properly based on the Path filter category of the displayed requests.
+
+
+
+
## Additional Information
::: info
diff --git a/src/guides/http_history.md b/src/guides/http_history.md
index 9c47b92..983b66f 100644
--- a/src/guides/http_history.md
+++ b/src/guides/http_history.md
@@ -20,6 +20,10 @@ To familiarize yourself with the HTTP History interface, continue below:
6. The `Enter an HTTPQL query...` input bar and `Advanced` button provide filtering options for the history feed. View the [HTTQL](/reference/httpql.md) and [Filters](/guides/filters.md) documentation for more information.
7. All active Filter Presets are listed here. Click on the cog wheel icon in the bottom-right corner of this pane to select/deselect filtering options.
+
+
+
+
## Modifications of Requests/Responses
**If you previously edited content directly in the Intercept interface:**
diff --git a/src/guides/match_replace.md b/src/guides/match_replace.md
index 08f0296..d47066c 100644
--- a/src/guides/match_replace.md
+++ b/src/guides/match_replace.md
@@ -19,6 +19,10 @@ There are numerous ways to create a new rule in the Match & Replace interface:
:::
+
+
+
+
## Adding a Custom Request Header
To add an additional header to a request, select the `Request Header` option from the `Section` dropdown menu. Then select the `Add` action. Provide the key name of the header and a string value.
diff --git a/src/guides/plugins.md b/src/guides/plugins.md
index 086acfb..8560ef5 100644
--- a/src/guides/plugins.md
+++ b/src/guides/plugins.md
@@ -14,6 +14,10 @@ These packages expand Caido's functionality, offering a means to futher customiz
4. Toggling the checkbox from filled to empty will enable/disable the associated Plugin.
5. To remove a plugin from your Caido Instance - click `Uninstall`.
+
+
+
+
::: info
If at least one Plugin is enabled - a new `Plugins` section within the left-hand side menu in Caido will be generated. From here, you can select specific Plugins to access additional information/functionality/usage instructions/etc.
:::
diff --git a/src/guides/replay_environment_variables.md b/src/guides/replay_environment_variables.md
index c86ae28..5e410e4 100644
--- a/src/guides/replay_environment_variables.md
+++ b/src/guides/replay_environment_variables.md
@@ -24,6 +24,12 @@ Then, depending on if the environment is new or existing, click on either the `C
+---
+
+
+
+
+
## Inserting an Environment Variable
With a defined environment variable, navigate to the [Replay](/guides/replay.md) interface. Within a request editing pane, click, hold, and drag the left mouse button over the value you want to be replaced and then click the `+` button to add it as a placeholder.
diff --git a/src/guides/upstream.md b/src/guides/upstream.md
index a5e53ed..419f924 100644
--- a/src/guides/upstream.md
+++ b/src/guides/upstream.md
@@ -13,7 +13,7 @@ In order to send traffic to another proxy from Caido:
:::
4. Click the `Add Proxy` button in the appropriate panel depending on the type.
-5. Input the hostname or IP address and port number of the upstream proxy.
+5. Input the hostname or IP address in the `Host` field and port number in the `Port` field of the upstream proxy.
6. Specify the scope of hosts that should be sent from Caido. To include all traffic, use `*`.
7. You can test the configuration by clicking the `Test` button.
@@ -24,8 +24,21 @@ In order to send traffic to another proxy from Caido:
+---
+
+
+
+
+
+---
+
+
+
+
+
::: tip TIPS
+- You can also set your credentials in the `Username` and `Password` fields.
- Ensure the upstream HTTP proxy is running using a different port than Caido.
- If both SOCKS and HTTP proxies are enabled, traffic will flow through the SOCKS proxy first, then through the HTTP proxy.
- You can enable/disable usage using the toggle switch associated with the table row of your saved configuration.
diff --git a/src/tutorials/discord_notification.md b/src/tutorials/discord_notification.md
new file mode 100644
index 0000000..cc86568
--- /dev/null
+++ b/src/tutorials/discord_notification.md
@@ -0,0 +1,252 @@
+# Sending a notification to Discord
+
+In this tutorial, we will learn how to use an Active Workflow to send a notification to Discord. This method can also be used with other types of workflows.
+
+We will use Caido's [HTTP Module](https://developer.caido.io/reference/modules/caido/http.html) which provides an implementation of the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). With this module, you can create and send asynchronous HTTP requests and handle their responses.
+
+::: warning NOTE
+The request and response objects of this module differ from those used in the [Backend SDK](https://developer.caido.io/reference/sdks/backend/) and [Workflow SDK](https://developer.caido.io/reference/sdks/workflow/). Due to this, their properties and methods differ as well. Additionally, they are not routed through the proxy and must adhere to the HTTP specification in order to be interpreted correctly.
+:::
+
+## Creating an Active Workflow
+
+To begin, navigate to the [Workflows](/guides/workflows.md) interface, select the `Active` tab, and click the `+ New workflow` button.
+
+
+
+Next, **click**, **hold** and **drag** a `Javascript` Node into the Workflow Editor field and make [Connections](/concepts/workflows_nodes.md#connecting-nodes) to the `Active Start` and `Active End` Nodes. Then click on the `Javascript` Node to access its detailed view.
+
+
+
+## Creating and Sending a Request
+
+Now, click within the coding environment, select all the existing code, and delete it.
+
+To send a request, you will first need to import the `Request` class and the `fetch()` function from the `caido:http` module.
+
+```js
+// Request object under the alias of FetchRequest.
+import { Request as FetchRequest, fetch } from "caido:http";
+```
+
+Next, define an asynchronous function and the parameters of your Discord message.
+
+```js
+export async function run(input, sdk) {
+ // Discord webhook data.
+ const webhookData = {
+ username: "Caido Bot",
+ avatar_url: "https://caido.io/images/logo.color.webp",
+ content: "Message from Caido Workflow",
+ embeds: [{
+ title: "Webhook Fetch Request",
+ description: "Hello World!",
+ color: 14329120,
+ fields: [
+ {
+ name: "Field A",
+ value: "Value A",
+ inline: true
+ },
+ {
+ name: "Field B",
+ value: "Value B",
+ inline: true
+ }
+ // You could also add elements from the request like
+ // {
+ // name: "Host",
+ // value: input.request.getHost(),
+ // inline: true
+ // },
+ ],
+ footer: {
+ text: "Sent via Caido"
+ },
+ timestamp: new Date().toISOString()
+ }]
+ };
+```
+
+::: tip
+[Visit this guide for a list of Discord message parameter options.](https://birdie0.github.io/discord-webhooks-guide/discord_webhook.html)
+:::
+
+Then, define the request object, using your Discord Webhook URL as the input parameter of the constructor and specify the HTTP method and Content-Type header in the [RequestOpts](https://developer.caido.io/reference/modules/caido/http.html#requestopts) parameter object.
+
+::: tip
+[Learn how to create a Discord Webhook.](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks)
+:::
+
+```js
+// Create a new request to Discord webhook.
+const fetchRequest = new FetchRequest("YOUR-DISCORD-WEBHOOK-URL", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(webhookData),
+});
+```
+
+We must await for the request to be sent and processed before we are able to obtain data from the response. By accessing the response properties, we can print the data to the backend logs.
+
+```js
+ try {
+ const response = await fetch(fetchRequest);
+
+ // Create response data object.
+ const responseData = {
+ status: response.status,
+ statusText: response.statusText,
+ headers: Object.fromEntries(response.headers.entries())
+ };
+
+ // Log the response data with proper formatting.
+ sdk.console.log("Response data:", JSON.stringify(responseData, null, 2));
+
+ // For Discord webhooks, 204 means success.
+ if (response.status === 204) {
+ return "Webhook sent successfully";
+ }
+
+ // If not 204, get the error details from response.
+ const errorBody = await response.text();
+ return `Webhook failed: ${errorBody}`;
+ } catch (error) {
+ return `Error: ${error.message}`;
+ }
+}
+```
+
+Finally, click the `Save` button in the bottom right corner of the Workflow Editor.
+
+::: tip
+To view the entire script, expand the following:
+
+
+Full Script
+
+```js
+// Request object under the alias of FetchRequest.
+import { Request as FetchRequest, fetch } from "caido:http";
+
+export async function run(input, sdk) {
+ // Discord webhook data.
+ const webhookData = {
+ username: "Caido Bot",
+ avatar_url: "https://caido.io/images/logo.color.webp",
+ content: "Message from Caido Workflow",
+ embeds: [
+ {
+ title: "Webhook Fetch Request",
+ description: "Hello World!",
+ color: 14329120,
+ fields: [
+ {
+ name: "Field A",
+ value: "Value A",
+ inline: true,
+ },
+ {
+ name: "Field B",
+ value: "Value B",
+ inline: true,
+ },
+ ],
+ footer: {
+ text: "Sent via Caido",
+ },
+ timestamp: new Date().toISOString(),
+ },
+ ],
+ };
+
+ // Create a new request to Discord webhook.
+ const fetchRequest = new FetchRequest("YOUR-DISCORD-WEBHOOK-URL", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(webhookData),
+ });
+
+ try {
+ const response = await fetch(fetchRequest);
+
+ // Create response data object.
+ const responseData = {
+ status: response.status,
+ statusText: response.statusText,
+ headers: Object.fromEntries(response.headers.entries()),
+ };
+
+ // Log the response data with proper formatting.
+ sdk.console.log("Response data:", JSON.stringify(responseData, null, 2));
+
+ // For Discord webhooks, 204 means success.
+ if (response.status === 204) {
+ return "Webhook sent successfully";
+ }
+
+ // If not 204, get the error details from response.
+ const errorBody = await response.text();
+ return `Webhook failed: ${errorBody}`;
+ } catch (error) {
+ return `Error: ${error.message}`;
+ }
+}
+```
+
+
+:::
+
+## Using the Active Workflow
+
+To use your newly created Workflow, right click on a request to open up the context menu. Hover over the `Run workflow` option and select the given name.
+
+
+
+Soon after, you will receive a message in your Discord channel.
+
+
+
+::: info
+Within the logs, the message will resemble:
+
+```
+2025-04-09T00:45:25.697833Z INFO main service|workflow: Executing workflow (g:58) as task
+2025-04-09T00:45:25.697858Z INFO main service|task: Running task
+2025-04-09T00:45:25.697862Z INFO main service|workflow: Workflow (g:58) task assigned ID: 26
+2025-04-09T00:45:26.134839Z INFO executor:0|arbiter:7 js|sdk: Response data:, {
+ "status": 204,
+ "statusText": "No Content",
+ "headers": {
+ "date": "Wed, 09 Apr 2025 00:45:26 GMT",
+ "content-type": "text/html; charset=utf-8",
+ "connection": "keep-alive",
+ "set-cookie": "_cfuvid=.E8ALL.xBWASGB1xARc0HgFKDv10bpItHt35AsAKJDE-1744159526028-0.0.1.1-604800000; path=/; domain=.discord.com; HttpOnly; Secure; SameSite=None",
+ "strict-transport-security": "max-age=31536000; includeSubDomains; preload",
+ "x-ratelimit-bucket": "3d2712a9e4fe17cc9d3fed4a8e672e5f",
+ "x-ratelimit-limit": "5",
+ "x-ratelimit-remaining": "4",
+ "x-ratelimit-reset": "1744159527",
+ "x-ratelimit-reset-after": "1",
+ "via": "1.1 google",
+ "alt-svc": "h3=\":443\"; ma=86400",
+ "cf-cache-status": "DYNAMIC",
+ "report-to": "{\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=ZIGoTFpSBw9RLoXTZmN0CKYNnESTcIYHDgSl42ygSs1E9uOAgvjN%2FMmks8w9SLiHDAzyu5n8WDyMRHcPiyYa0LkUcpMyXEaoPd0c7HE9rHkCh24fR55k2qRmgTJL\"}],\"group\":\"cf-nel\",\"max_age\":604800}",
+ "nel": "{\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}",
+ "x-content-type-options": "nosniff",
+ "reporting-endpoints": "csp-sentry=\"https://o64374.ingest.sentry.io/api/5441894/security/?sentry_key=8fbbce30bf5244ec9429546beef21870&sentry_environment=stable\"",
+ "content-security-policy": "frame-ancestors 'none'; default-src https://o64374.ingest.sentry.io; report-to csp-sentry; report-uri https://o64374.ingest.sentry.io/api/5441894/security/?sentry_key=8fbbce30bf5244ec9429546beef21870&sentry_environment=stable",
+ "server": "cloudflare",
+ "cf-ray": "92d5fb4c58d5f7ab-LAX"
+ }
+}
+2025-04-09T00:45:26.135041Z INFO executor:0|arbiter:7 service|task: Task (26) done
+2025-04-09T00:45:26.135079Z INFO main service|task: Finishing task 26
+
+```
+
+:::