Skip to content
Filters

Filters

Filters transform values when outputting variables. Chain them with the pipe | character.

INFO

The examples below use vuln. as the loop variable (e.g. vuln.severity). This assumes you are inside a {% for vuln in vulnerabilities %} loop.

Date formatting

formatDate

Formats a date value.

liquid
{{ dates.startDate | formatDate: 'short' }}   <!-- 01/15/2025 -->
{{ dates.startDate | formatDate: 'long' }}    <!-- January 15, 2025 -->
{{ dates.startDate | formatDate: 'full' }}    <!-- Wednesday, January 15, 2025 -->
FormatOutput
short01/15/2025
longJanuary 15, 2025
fullWednesday, January 15, 2025

String manipulation

capitalize, uppercase, lowercase

liquid
{{ "hello world" | capitalize }}   <!-- Hello world -->
{{ report.title | uppercase }}     <!-- PENETRATION TEST REPORT -->
{{ report.title | lowercase }}  <!-- critical -->

Score formatting

score

Formats a numeric value to one decimal place. Returns 0.0 for null or undefined values.

liquid
{{ vuln.cvss.score | score }}   <!-- 7.5 -->
{{ vuln.cvss.baseScore | score }}

cvssMetric

Returns Not Defined for null or empty CVSS metric values.

liquid
{{ vuln.cvss.AV | cvssMetric }}   <!-- Network -->
{{ vuln.cvss.E | cvssMetric }}    <!-- Not Defined (if empty) -->

Color mapping

These filters return hex color codes that can be used in inline styles.

severityColor / severityBackgroundColor

Map a severity string to a color. Use severityColor for text and severityBackgroundColor for backgrounds.

These are typically used in table cells where you can set the cell's color via the visual editor, or in inline styles:

liquid
{{ vuln.severity | severityColor }}
{{ vuln.severity | severityBackgroundColor }}

textColor / backgroundColor

Map a numeric CVSS score to a color.

RangeSeverity
9.0 – 10.0Critical
7.0 – 8.9High
4.0 – 6.9Medium
0.1 – 3.9Low
0None
liquid
{{ vuln.cvss.score | backgroundColor }}
{{ vuln.cvss.score | textColor }}

mapColor / mapBgColor

Map arbitrary values to custom colors. Format: 'key1:#hex1,key2:#hex2,_default:#hex'.

liquid
{{ vuln.remediationComplexity | mapColor: 'Easy:#22c55e,Medium:#eab308,Hard:#ef4444,_default:#6b7280' }}
{{ vuln.priority | mapBgColor: 'P1:#dc2626,P2:#ea580c,P3:#ca8a04,P4:#2563eb' }}

Matching is case-insensitive. Use _default for a fallback color.

Value mapping

mapValue

Translate or map a value to a different string. Format: 'key1:value1,key2:value2,_default:fallback'.

liquid
{{ vuln.severity | mapValue: 'Critical:Critique,High:Élevé,Medium:Moyen,Low:Faible,Info:Information' }}
{{ vuln.remediationComplexity | mapValue: 'Easy:Facile,Medium:Moyen,Hard:Difficile,_default:Inconnu' }}

Matching is case-insensitive. Returns the original value if no match is found and no _default is set.

Sorting

sort_by

Sort an array by a property. Supports nested properties with dot-notation.

liquid
<!-- Sort by CVSS score -->
{% for vuln in vulnerabilities | sort_by: 'cvss.score' %}
  {{ vuln.title }} — {{ vuln.cvss.score | score }}
{% endfor %}

<!-- Sort alphabetically by title -->
{% for vuln in vulnerabilities | sort_by: 'title' %}
  {{ vuln.title }}
{% endfor %}

sort_multi

Sort by multiple keys with custom value ordering. Format: 'property1:value1|value2;property2:value1|value2'.

Semicolons separate sort keys, colons separate property from value order, pipes separate values.

liquid
<!-- Sort by severity (Critical first), then by CVSS score -->
{% for vuln in vulnerabilities | sort_multi: 'severity:Critical|High|Medium|Low|Info;cvss.score:desc' %}
  {{ vuln.severity }} — {{ vuln.title }} ({{ vuln.cvss.score | score }})
{% endfor %}

Filtering by vulnerability template

When a report uses more than one vulnerability template (for example, a Web template and a Mobile template on the same report), every finding still ends up in the same vulnerabilities array. Each finding carries a templateName field with the name of the vulnerability template it was created from, so you can split or filter the list inside your report template.

Loop only findings from one template

Use a Liquid if inside the loop to render a section per template:

liquid
<!-- Web findings -->
{% for vuln in vulnerabilities %}
  {% if vuln.templateName == 'Web' %}
    {{ forloop.index }}. {{ vuln.title }} — {{ vuln.severity }}
    {{ vuln.description }}
  {% endif %}
{% endfor %}

<!-- Mobile findings -->
{% for vuln in vulnerabilities %}
  {% if vuln.templateName == 'Mobile' %}
    {{ forloop.index }}. {{ vuln.title }} — {{ vuln.severity }}
    {{ vuln.description }}
  {% endif %}
{% endfor %}

Pre-filter with the where filter

The standard Liquid where filter returns a sub-array, which keeps forloop.index and size accurate for each group:

liquid
{% assign web_vulns = vulnerabilities | where: 'templateName', 'Web' %}
{% assign mobile_vulns = vulnerabilities | where: 'templateName', 'Mobile' %}

Web findings: {{ web_vulns | size }}
Mobile findings: {{ mobile_vulns | size }}

{% for vuln in web_vulns %}
  {{ forloop.index }}. {{ vuln.title }}
{% endfor %}

You can chain it with sort_by or sort_multi to order each group independently:

liquid
{% assign web_vulns = vulnerabilities | where: 'templateName', 'Web' | sort_by: 'cvss.score' %}

TIP

The name must match the vulnerability template name exactly (case-sensitive). If you rename a vulnerability template, also update any templateName comparisons in your report templates.

Standard Liquid filters

All standard LiquidJS filters are also available. Some commonly used ones:

FilterDescriptionExample
sizeArray length or string length{{ vulnerabilities | size }}
plusAdd a number{{ stats.criticalCount | plus: stats.highCount }}
minusSubtract a number{{ stats.totalVulnerabilities | minus: stats.informativeCount }}
defaultFallback value if empty{{ client.logo | default: '/placeholder.png' }}
joinJoin array items{{ vuln.tags | join: ', ' }}
replaceReplace text{{ report.title | replace: 'Draft', 'Final' }}
truncateTruncate to length{{ vuln.description | truncate: 100 }}
strip_htmlRemove HTML tags{{ vuln.description | strip_html }}
newline_to_brConvert newlines to <br>{{ text | newline_to_br }}