Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 125 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,25 +122,139 @@ icon:
> [!NOTE]
> You can highlight important information in your articles or docs using different types of callouts (also known as admonitions – or alerts, as used in [the Hugo docs](https://gohugo.io/render-hooks/blockquotes/#alerts)).

The examples below use the same syntax as in Github Markdown. The template responsible for rendering them is at `site/layouts/_default/_markup/render-blockquote.html`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I haven't deleted the render hook. So, it's still possible to use the old syntax. Please confirm that I can remove it. Or let me know if you'd like to keep it.

For compatibility with both content and layout files, we use a mix of shortcodes and partials to display blockquote alerts. Partials work in layout, but not content files. Shortcodes work in content, but not layout files. Use the partial in layout files, and the shortcode (which internally calls the partial) in content files.

The partial is at `site/layouts/partials/blockquote-alert.html`, and the shortcode is at `site/layouts/shortcodes/blockquote-alert.html`.

There are five available alert types as shown in the examples below:

- note
- tip
- important
- warning
- caution

You can pass in simple string content or complex content with multiple paragraphs and nested elements. Omit the `title` parameter to keep the alert type as the default title (for example, a note alert will have "Note" as its title):

```md
<!-- Shortcodes in content files -->

{{< blockquote-alert type="note" title="Optional custom title">}}
Useful information that users should know, even when skimming content.
{{< /blockquote-alert >}}

{{< blockquote-alert type="tip" title="Optional custom title">}}
Helpful advice for doing things better or more easily.

This is some **bold text** and _italic_ text.

This is a third paragraph in the same alert, followed by list items below.

- List item 1
- List item 2
{{< /blockquote-alert >}}

{{< blockquote-alert type="important" title="Optional custom title">}}
Key information users need to know to achieve their goal.
{{< /blockquote-alert >}}

{{< blockquote-alert type="warning" title="Optional custom title">}}
Urgent info that needs immediate user attention to avoid problems.
{{< /blockquote-alert >}}

{{< blockquote-alert type="caution" title="Optional custom title">}}
Advises about risks or negative outcomes.
{{< /blockquote-alert >}}
```
> [!NOTE]
> Useful information that users should know, even when skimming content.

> [!TIP]
> Helpful advice for doing things better or more easily.
In layout files, call the partial directly. Anything passed to the `content` parameter is parsed as Markdown. To pass raw HTML instead, use the `html` parameter. Again, the title parameter is optional and will default to the alert type:

> [!IMPORTANT]
> Key information users need to know to achieve their goal.
```html
<!-- Partials in layout files -->

<!-- Anything passed via `content` is interpreted as Markdown -->

{{ partial "blockquote-alert.html" (dict
"type" "note"
"title" "Optional custom title"
"content" "Useful information that users should know, even when skimming content."
) }}

{{ partial "blockquote-alert.html" (dict
"type" "tip"
"title" "Optional custom title"
"content" "Helpful advice for doing things better or more easily."
) }}

{{ partial "blockquote-alert.html" (dict
"type" "important"
"title" "Optional custom title"
"content" "Key information users need to know to achieve their goal."
) }}

<!-- Pass HTML -->
{{ partial "blockquote-alert.html" (dict
"type" "warning"
"title" "Optional custom title"
"html" "<p>Urgent info that needs immediate user attention to avoid problems.</p>"
) }}

{{ partial "blockquote-alert" (dict
"type" "caution"
"title" "Optional custom title"
"html" "<p>Advises about <strong>risks</strong> or negative outcomes.</p>"
) }}
```

> [!WARNING]
> Urgent info that needs immediate user attention to avoid problems.
You can assign content to a variable before passing it to the partial, which helps with formatting in longer templates:

> [!CAUTION]
> Advises about risks or negative outcomes.
```html
<!-- You can wrap your markdown content in backticks if it doesn't itself contain backticks -->
<!-- Note that indented lines could be interpreted as a preformatted code block. -->
{{ $alertContent := `This is a tip with **bold text** and _italic_ text.

This is a second paragraph in the same alert.

- List item 1
- List item 2
`}}

{{ partial "blockquote-alert.html" (dict
"type" "tip"
"title" "Optional custom title"
"content" $alertContent
) }}

<!-- Concatenate multi-line Markdown strings -->
{{ $alertContent := add
"This is a tip with **bold text** and _italic_ text.\n\n"
"This is a second paragraph in the same alert.\n"
"- List item 1\n"
"- List item 2\n\n"
"`Here's some text in backticks.`"
}}

{{ partial "blockquote-alert.html" (dict
"type" "tip"
"title" "Optional custom title"
"content" $alertContent
) }}
```

> [!IMPORTANT]
> When working with complex content, make sure to handle line breaks properly within the strings passed to the `content` or `html` parameters. For example, the following will throw a parse error (`html: overlay: parse failed unterminated quoted string in action`):

```
{{ partial "blockquote-alert" (dict
"type" "caution"
"title" "Be Careful!"
"html" "<p>This is a <strong>caution</strong> message.</p>
<p>It has multiple paragraphs.</p>"
) }}
```

To avoid this, you can either keep everything on a single line or use string concatenation.

#### Layouts
For controlling what HTML is rendered, you need to work with the site templates. In the directory, `site/layouts/`, you'll find a number of HTML files with various template tags. The first file to check out is `site/layouts/_default/baseof.html` - this is the base layout Hugo uses to build your site that templates extend. Hugo has a lookup order for associating a content entry to a template. A single entry whose type is post (`type: post`), Hugo will look for a layout in `site/layouts/post/single.html`, and if that does not exist, it will fallback to `site/layouts/_default/single.html`.

Expand Down
10 changes: 6 additions & 4 deletions site/content/blog/2025-04-02-zap-updates-march-2025/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ authors:

## Highlights

> [!IMPORTANT]
> The big news last month was the release of [2.16.1](/blog/2025-03-25-zap-2-16-1/)!
{{< blockquote-alert type="important">}}
The big news last month was the release of [2.16.1](/blog/2025-03-25-zap-2-16-1/)!
{{< /blockquote-alert >}}

As part of this release the [Script Console](/docs/desktop/addons/script-console/) now uses the main
[Output](/docs/desktop/ui/tabs/output/) tab instead of its own "Script Output" panel.
Expand Down Expand Up @@ -45,8 +46,9 @@ The following significant changes have been made to this website:
* A new [Script Security](/docs/getting-further/script-security/) advanced guide
* Even more [Authentication Tests](/docs/scans/auth/)

> [!NOTE]
> We now have the option to highlight important information, as demonstrated here!
{{< blockquote-alert type="note">}}
We now have the option to highlight important information, as demonstrated here!
{{< /blockquote-alert >}}

## GitHub Pulse
Here are some statistics for the two main ZAP repositories:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@ Copy-paste the lab URL into the *URL to explore* field and launch your browser w

![launch-test-site-ZAP-configured-browser.png](images/launch-test-site-ZAP-configured-browser.png)

> [!NOTE]
> If you have any issues launching your browser from ZAP, see the following pages for help. ZAP uses add-ons to enhance its core features, including ones which provide webdrivers for interfacing with supported browsers. These are installed by default and expose some configurable options:
>
> 1. [How can I fix 'browser was not found'?](/faq/how-can-i-fix-browser-was-not-found/) - ZAP Docs (FAQ)
> 2. [Manual Explore](/docs/desktop/addons/quick-start/#manual-explore) - ZAP Docs
> 3. [Selenium](/docs/desktop/addons/selenium/) - ZAP Docs
{{< blockquote-alert type="note">}}
If you have any issues launching your browser from ZAP, see the following pages for help. ZAP uses add-ons to enhance its core features, including ones which provide webdrivers for interfacing with supported browsers. These are installed by default and expose some configurable options:

1. [How can I fix 'browser was not found'?](/faq/how-can-i-fix-browser-was-not-found/) - ZAP Docs (FAQ)
2. [Manual Explore](/docs/desktop/addons/quick-start/#manual-explore) - ZAP Docs
3. [Selenium](/docs/desktop/addons/selenium/) - ZAP Docs
{{< /blockquote-alert >}}

Assuming you’ve opened the lab in a browser configured to proxy through ZAP, let’s try to log in with a random password. We want to capture a POST request we can work with in ZAP. I’ll try “randompass”. We’re notified that this is an “Incorrect password”, which is expected:

Expand Down Expand Up @@ -96,8 +97,9 @@ After one minute, we can indeed make more login attempts. The idea is that if we

If we enter our own credentials, `wiener:peter`, on every third login attempt, the IP block never activates. Each successful login resets the counter tracking the number of failed login attempts. We can keep going until we’ve tried enough passwords from our wordlist to find the right one for Carlos' account.

> [!NOTE]
> This bypass — taking advantage of a logic flaw to reset the failure counter — enables us to brute-force Carlos’ password and successfully solve this lab. Although not the point of the lab, we can also wait out the IP block since we’re dealing with only a few credentials. This is covered in “Method 2: Wait Out the IP Block”.
{{< blockquote-alert type="note">}}
This bypass — taking advantage of a logic flaw to reset the failure counter — enables us to brute-force Carlos’ password and successfully solve this lab. Although not the point of the lab, we can also wait out the IP block since we’re dealing with only a few credentials. This is covered in “Method 2: Wait Out the IP Block”.
{{< /blockquote-alert >}}

What about changing our IP address? I used the [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For) header successfully in another lab. But the server here appears to block IPs based on the client's actual IP address (determined by the network layer rather than HTTP headers from the application layer), which makes sense in the context of rate-limiting. Rotating IP addresses via a proxy or VPN could work, but we won’t explore that here.

Expand Down Expand Up @@ -564,8 +566,9 @@ All functions, except the `log` function, are part of a required interface that

![implementation-error.png](images/implementation-error.png)

> [!NOTE]
> Refer to the default templates for the interfaces required for each script type. You can find these in the Templates section of the Scripts tab. They include documentation comments describing each function and its parameters. You can also create new scripts from the templates.
{{< blockquote-alert type="note">}}
Refer to the default templates for the interfaces required for each script type. You can find these in the Templates section of the Scripts tab. They include documentation comments describing each function and its parameters. You can also create new scripts from the templates.
{{< /blockquote-alert >}}

You can save the file now. Also, check that the script is enabled, as disabled scripts won’t be available for selection when needed. If you missed the *Enable* checkbox earlier, you can right-click the filename in the *Scripts* tab and select *Enable Script(s)*.

Expand All @@ -583,10 +586,11 @@ After you open the *Add Payload* dialog, you can add the Payload Generator scrip

Save the payload and return to the main Fuzzer dialog. Then, run the Fuzzer with *Start Fuzzer*.

> [!IMPORTANT]
> You might notice that even though the payloads are generated correctly (as the logs in the script output panel show), the requests are sent in the wrong order. This causes an unexpected IP block early on. As a result, most of the requests are rejected with the message: `You have made too many incorrect login attempts. Please try again in 1 minute(s).`
>
> This is due to the Fuzzer’s concurrency settings. You can enable sequential execution by setting the number of execution threads to 1. However, this slows down the Fuzzer a great deal. An alternative is to throttle requests with a small delay of 100–200 milliseconds. See [Options Fuzzer screen](/docs/desktop/addons/fuzzer/options/) for more detail.
{{< blockquote-alert type="important">}}
You might notice that even though the payloads are generated correctly (as the logs in the script output panel show), the requests are sent in the wrong order. This causes an unexpected IP block early on. As a result, most of the requests are rejected with the message: `You have made too many incorrect login attempts. Please try again in 1 minute(s).`

This is due to the Fuzzer’s concurrency settings. You can enable sequential execution by setting the number of execution threads to 1. However, this slows down the Fuzzer a great deal. An alternative is to throttle requests with a small delay of 100–200 milliseconds. See [Options Fuzzer screen](/docs/desktop/addons/fuzzer/options/) for more detail.
{{< /blockquote-alert >}}

You can skip over the next section and head to [Have Username, Got Password](#have-username-got-password).

Expand Down Expand Up @@ -715,8 +719,9 @@ You can optionally move the script to the top of the processor list. Then, run t

Once the Fuzzer is done, we can inspect the results. We’re looking for indications of a successful login. So, we’ll sort the results in descending order using the status code column (simply “*Code”* in the UI).

> [!NOTE]
> Both of these solutions are valid. As you might have noticed if you’ve solved a lab more than once, different lab instances can have different password solutions. So, you could see different passwords than shown below.
{{< blockquote-alert type="note">}}
Both of these solutions are valid. As you might have noticed if you’ve solved a lab more than once, different lab instances can have different password solutions. So, you could see different passwords than shown below.
{{< /blockquote-alert >}}

### Method 1: Interleave Wordlists With Valid Credentials

Expand Down
5 changes: 3 additions & 2 deletions site/content/docs/getting-further/script-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ For more details on ZAP’s security posture see the
### Script Capabilities
As noted on the [Script Console](/docs/desktop/addons/script-console/) page:

> [!WARNING]
> Scripts run with the same permissions as ZAP, so do not run any scripts that you do not trust!
{{< blockquote-alert type="warning">}}
Scripts run with the same permissions as ZAP, so do not run any scripts that you do not trust!
{{< /blockquote-alert >}}

All scripts can call other scripts and any command line tools that are accessible to them based on OS permissions.
Scripts can access any online services unless restricted by firewalls or similar.
Expand Down
5 changes: 3 additions & 2 deletions site/content/faq/somethings-not-working-what-should-i-do.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,6 @@ You can chat with the ZAP team on [Slack](/slack/), if you have not already join
You can raise issues (bugs or new features) at the [issue
tracker](https://github.com/zaproxy/zaproxy/issues/new/choose).

> [!WARNING]
> Please do not ask questions as issues - they will be closed and you will be redirected to the [ZAP user group](https://groups.google.com/group/zaproxy-users).
{{< blockquote-alert type="warning">}}
Please do not ask questions as issues - they will be closed and you will be redirected to the [ZAP user group](https://groups.google.com/group/zaproxy-users).
{{< /blockquote-alert >}}
38 changes: 17 additions & 21 deletions site/layouts/page/download.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,27 +54,23 @@ <h2 id="main">{{ .title }}</h2>
</ul>
{{ end }}

<blockquote class="alert alert-warning">
<p class="alert-heading">
⚠️ Warning - The ZAP releases are currently unsigned
</p>
<div class="alert-content">
<p>
On <strong>Windows</strong>, you will see a message like:
<code>
ZAP_&lt;version&gt;_windows.exe isn't commonly downloaded.
Make sure you trust ZAP_&lt;version&gt;_windows.exe before you open it.
</code><br>
To circumvent this warning, you would need to click on <strong>...</strong> and then <strong>Keep</strong>,
then <strong>Show more</strong> and then <strong>Keep anyway</strong>.
<p>
On <strong>macOS</strong>, you will see a message like:
<code>"ZAP.app" cannot be opened because the developer cannot be verified.</code><br>
To circumvent this warning, you would need to go to <strong>System Preferences</strong> &gt; <strong>Security & Privacy</strong>
at the bottom of the dialog. You will see a message saying that "ZAP" was blocked.
Next to it, if you trust the downloaded installer, you can click <strong>Open anyway</strong>.
</div>
</blockquote>
{{ $alertContent := add
"On **Windows**, you will see a message like: "
"`ZAP_<version>_windows.exe isn't commonly downloaded. Make sure you trust ZAP_<version>_windows.exe before you open it.`\n\n"
"To circumvent this warning, you would need to click on **...** and then **Keep**, then "
"**Show more** and then **Keep anyway**.\n\n"
"On **macOS**, you will see a message like: "
"`\"ZAP.app\" cannot be opened because the developer cannot be verified.`\n\n"
"To circumvent this warning, you would need to go to **System Preferences** > **Security & Privacy** at "
"the bottom of the dialog. You will see a message saying that\"ZAP\" was blocked. Next to it, if you trust the "
"downloaded installer, you can click **Open anyway**."
}}

{{ partial "blockquote-alert.html" (dict
"type" "warning"
"title" "Warning - The ZAP releases are currently unsigned"
"content" $alertContent
) }}
</div>
</section>

Expand Down
43 changes: 43 additions & 0 deletions site/layouts/partials/blockquote-alert.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{{ $emojis := dict
"caution" ":bangbang:"
"important" ":information_source:"
"note" ":memo:"
"tip" ":bulb:"
"warning" ":warning:"
}}

{{ $type := .type | default "note" }}
{{ $title := .title | default "" }}
{{ $content := .content | default "" }}
{{ $html := .html | default "" }}
Comment on lines +9 to +12
Copy link
Contributor Author

@Wryhder Wryhder Jun 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This got a bit more complex than I intended. I was looking for a way to pass the alert string in layout files without having to write so many HTML tags as in this example (while ensuring Markdown and HTML still got parsed correctly whether coming from the partial or shortcode):

(sample conversion from download.html)


{{ $alertContent := add
  "<p>On <strong>Windows</strong>, you will see a message like: "
  "<code>ZAP_&lt;version&gt;_windows.exe isn't commonly downloaded. Make sure you trust ZAP_&lt;version&gt;_windows.exe before you open it.</code><br>"
  "To circumvent this warning, you would need to click on <strong>...</strong> and then <strong>Keep</strong>, then "
  "<strong>Show more</strong> and then <strong>Keep anyway</strong>.</p>"
  "<p>On <strong>macOS</strong>, you will see a message like: "
  "<code>&quot;ZAP.app&quot; cannot be opened because the developer cannot be verified.</code><br>"
  "To circumvent this warning, you would need to go to <strong>System Preferences</strong> &gt; <strong>Security & Privacy</strong> at "
  "the bottom of the dialog. You will see a message saying that &quot;ZAP&quot; was blocked. Next to it, if you trust the "
  "downloaded installer, you can click <strong>Open anyway</strong>.</p>"
}}

{{ partial "blockquote-alert.html" (dict
  "type" "warning"
  "html" $alertContent
) }}

I ended up creating two separate content parameters for the partial. html for HTML and content for markdown (this is also the parameter used for the shortcode).


{{/* Handle inner content from shortcodes */}}
{{ if .inner }}
{{ $content = .inner }}
{{ end }}

{{ if $type }}
<blockquote class="alert alert-{{ $type }}">
<p class="alert-heading">
{{ transform.Emojify (index $emojis $type) }}
{{ if $title }}
{{ $title }}
{{ else }}
{{ or (i18n $type) (title $type) }}
{{ end }}
</p>
<div class="alert-content">
{{ if $html }}
{{ $html | safeHTML }}
{{ else if $content }}
{{ $content | markdownify }}
{{ else }}
{{ i18n "no-content" }}
{{ end }}
</div>
</blockquote>
{{ else }}
<blockquote>
{{ $content | markdownify }}
</blockquote>
{{ end }}
9 changes: 9 additions & 0 deletions site/layouts/shortcodes/blockquote-alert.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{{ $type := .Get "type" | default "note" }}
{{ $title := .Get "title" | default "" }}
{{ $inner := .Inner }}

{{ partial "blockquote-alert" (dict
"type" $type
"title" $title
"inner" $inner
) }}