# 🧠 Master Guide to Using NVIDIA Garak for LLM Vulnerability Testing

Author: Harshit Rajpal, Security Engineer, Bureau Veritas Cybersecurity North America

## Introduction

In this guide, we will explore **Garak** – an open-source **Generative AI Red-teaming and Assessment Kit** by NVIDIA – and how to use it for scanning Large Language Models (LLMs) for vulnerabilities. We’ll cover everything from installation and setup to running scans, focusing on key features like connecting Garak to different LLM interfaces (including a local REST API chatbot), using specific probes (e.g. jailbreaking attacks), customizing prompts, speeding up scans, understanding Garak’s components, writing your own plugin, and interpreting Garak’s output reports. This comprehensive, step-by-step walkthrough will feel like a technical whitepaper, complete with code examples, command-line usage, and references to official documentation and community insights.

## Table of Content

<table><thead><tr><th width="102">S. No.</th><th>Section</th></tr></thead><tbody><tr><td>1</td><td><a href="#id-1.-installation-and-environment-setup">Installation and Environment Setup</a></td></tr><tr><td>2</td><td><a href="#id-2.-getting-started-with-garak">Getting Started With Garak</a></td></tr><tr><td>3</td><td></td></tr><tr><td></td><td></td></tr><tr><td></td><td></td></tr><tr><td></td><td></td></tr><tr><td></td><td></td></tr></tbody></table>

## 1. Installation and Environment Setup

Since Garak has its own dependencies, this guide will use Conda. Conda is a powerful command-line tool for package and environment management that runs on Windows, macOS, and Linux.

### System Requirements (recommended)

* **Python:** 3.10
* **OS:** Windows 10+, Linux, or macOS
* **RAM:** Minimum 8GB (more if using local LLMs via Ollama or transformers)

Optional:

* **GPU:** NVIDIA GPU with CUDA for local model acceleration
* **Anaconda**: [Latest Release](https://docs.conda.io/projects/conda/en/stable/user-guide/install/index.html)
* **git**
* **Ollama:** [Latest Release](https://ollama.com/)

Let's get started with the setup.

I will be using a Windows 10 host in this guide; however, feel free to use the supplemental commands for your specific OS. Some of the key alternate commands will be given here.

First, let's get Conda up and running. You can choose your installer [here](https://repo.anaconda.com/archive/) and then use the following commands for download and installation.

<pre class="language-powershell" data-title="Windows" data-overflow="wrap"><code class="lang-powershell"><strong># Navigate to your project folder. I am creating a 'Downloads' folder within it.
</strong><strong>mkdir Downloads
</strong>
wget "https://repo.anaconda.com/archive/Anaconda3-2025.06-0-Windows-x86_64.exe" -outfile "./Downloads/Anaconda3-2025.06-0-Windows-x86_64.exe"

#Run the installer via GUI
</code></pre>

<pre class="language-bash" data-title="Linux" data-overflow="wrap"><code class="lang-bash"># Navigate to your project folder. I am creating a 'Downloads' folder within it.
<strong>mkdir Downloads &#x26;&#x26; cd Downloads
</strong>
wget https://repo.anaconda.com/archive/Anaconda3-2025.06-1-Linux-x86_64.sh

chmod +x Anaconda3-2025.06-1-Linux-x86_64.sh &#x26;&#x26; ./Anaconda3-2025.06-1-Linux-x86_64.sh
</code></pre>

Follow the standard installation process. Once done, within your project folder (mine would be C:\Users\hex\Desktop\Garak), check a valid Anaconda installation via the `conda` command.

<figure><img src="https://62284611-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MSvRnuhl_P5WCd1fZEn%2Fuploads%2FBcMeD6AN0lIIjSUzwfMt%2Fimage.png?alt=media&#x26;token=caba60fe-d0bf-4d43-b220-65b36adaff65" alt=""><figcaption></figcaption></figure>

We are ready to set up a new environment for Garak.

{% code title="Windows and Linux" overflow="wrap" %}

```powershell
conda create --name garak python=3.10
conda activate garak
git clone https://github.com/NVIDIA/garak.git
cd garak
python -m pip install -e .
```

{% endcode %}

Once installed, Garak provides a command-line interface. To see basic usage, run `garak -h`

```
garak LLM vulnerability scanner v0.13.2.pre1 ( https://github.com/NVIDIA/garak ) at 2025-10-13T21:40:19.630483
usage: python -m garak [-h] [--verbose] [--report_prefix REPORT_PREFIX] [--narrow_output]
                       [--parallel_requests PARALLEL_REQUESTS] [--parallel_attempts PARALLEL_ATTEMPTS]
                       [--skip_unknown] [--seed SEED] [--deprefix] [--eval_threshold EVAL_THRESHOLD]
                       [--generations GENERATIONS] [--config CONFIG] [--target_type TARGET_TYPE]
                       [--target_name TARGET_NAME] [--probes PROBES] [--probe_tags PROBE_TAGS] [--detectors DETECTORS]
                       [--extended_detectors] [--buffs BUFFS] [--buff_option_file BUFF_OPTION_FILE |
                       --buff_options BUFF_OPTIONS] [--detector_option_file DETECTOR_OPTION_FILE |
                       --detector_options DETECTOR_OPTIONS] [--generator_option_file GENERATOR_OPTION_FILE |
                       --generator_options GENERATOR_OPTIONS] [--harness_option_file HARNESS_OPTION_FILE |
                       --harness_options HARNESS_OPTIONS] [--probe_option_file PROBE_OPTION_FILE |
                       --probe_options PROBE_OPTIONS] [--taxonomy TAXONOMY] [--plugin_info PLUGIN_INFO]
                       [--list_probes] [--list_detectors] [--list_generators] [--list_buffs] [--list_config]
                       [--version] [--report REPORT] [--interactive] [--generate_autodan] [--fix]

LLM safety & security scanning tool

options:
  -h, --help            show this help message and exit
  --verbose, -v         add one or more times to increase verbosity of output during runtime
  --report_prefix REPORT_PREFIX
                        Specify an optional prefix for the report and hit logs
  --narrow_output       give narrow CLI output
  --parallel_requests PARALLEL_REQUESTS
                        How many generator requests to launch in parallel for a given prompt. Ignored for models that
                        support multiple generations per call.
  --parallel_attempts PARALLEL_ATTEMPTS
                        How many probe attempts to launch in parallel. Raise this for faster runs when using non-local
                        models.
  --skip_unknown        allow skip of unknown probes, detectors, or buffs
  --seed, -s SEED       random seed
  --deprefix            remove the prompt from the front of generator output
  --eval_threshold EVAL_THRESHOLD
                        minimum threshold for a successful hit
  --generations, -g GENERATIONS
                        number of generations per prompt
  --config CONFIG       YAML config file for this run
  --target_type, -t, --model_type, -m TARGET_TYPE
                        module and optionally also class of the generator, e.g. 'huggingface', or 'openai'
  --target_name, --model_name, -n TARGET_NAME
                        name of the target, e.g. 'timdettmers/guanaco-33b-merged'
  --probes, -p PROBES   list of probe names to use, or 'all' for all (default).
  --probe_tags PROBE_TAGS
                        only include probes with a tag that starts with this value (e.g. owasp:llm01)
  --detectors, -d DETECTORS
                        list of detectors to use, or 'all' for all. Default is to use the probe's suggestion.
  --extended_detectors  If detectors aren't specified on the command line, should we run all detectors? (default is
                        just the primary detector, if given, else everything)
  --buffs, -b BUFFS     list of buffs to use. Default is none
  --buff_option_file, -B BUFF_OPTION_FILE
                        path to JSON file containing options to pass to buff
  --buff_options BUFF_OPTIONS
                        options to pass to buff, formatted as a JSON dict
  --detector_option_file, -D DETECTOR_OPTION_FILE
                        path to JSON file containing options to pass to detector
  --detector_options DETECTOR_OPTIONS
                        options to pass to detector, formatted as a JSON dict
  --generator_option_file, -G GENERATOR_OPTION_FILE
                        path to JSON file containing options to pass to generator
  --generator_options GENERATOR_OPTIONS
                        options to pass to generator, formatted as a JSON dict
  --harness_option_file, -H HARNESS_OPTION_FILE
                        path to JSON file containing options to pass to harness
  --harness_options HARNESS_OPTIONS
                        options to pass to harness, formatted as a JSON dict
  --probe_option_file, -P PROBE_OPTION_FILE
                        path to JSON file containing options to pass to probe
  --probe_options PROBE_OPTIONS
                        options to pass to probe, formatted as a JSON dict
  --taxonomy TAXONOMY   specify a MISP top-level taxonomy to be used for grouping probes in reporting. e.g. 'avid-
                        effect', 'owasp'
  --plugin_info PLUGIN_INFO
                        show info about one plugin; format as type.plugin.class, e.g. probes.lmrc.Profanity
  --list_probes         list all available probes. Usage: combine with --probes/-p to filter for probes that will be
                        activated based on a `probe_spec`, e.g. '--list_probes -p dan' to show only active 'dan'
                        family probes.
  --list_detectors      list available detectors. Usage: combine with --detectors/-d to filter for detectors that will
                        be activated based on a `detector_spec`, e.g. '--list_detectors -d misleading.Invalid' to show
                        only that detector.
  --list_generators     list available generation model interfaces
  --list_buffs          list available buffs/fuzzes
  --list_config         print active config info (and don't scan)
  --version, -V         print version info & exit
  --report, -r REPORT   process garak report into a list of AVID reports
  --interactive, -I     Enter interactive probing mode
  --generate_autodan    generate AutoDAN prompts; requires --prompt_options with JSON containing a prompt and target
  --fix                 Update provided configuration with fixer migrations; requires one of --config /
                        --*_option_file, / --*_options

See https://github.com/NVIDIA/garak
```

## 2. Getting Started With Garak

To quickly test Garak’s setup with a sample LLM generator and a probe.

This uses Garak’s built-in test components:

* **Generator:** `test.Blank` – a mock model which can be specified with `--target_type`
* **Probe:** `test.Blank` – sends a dummy input, which can be specified with `--probes`

```powershell
garak --target_type test.Blank --probes test.Test
```

<figure><img src="https://62284611-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MSvRnuhl_P5WCd1fZEn%2Fuploads%2FzYJaGq4uimcbAW6587Gt%2Fimage.png?alt=media&#x26;token=45ea005a-dcbb-4a11-a927-5e0d057bf807" alt=""><figcaption></figcaption></figure>

As you may have observed, the JSON and HTML summary reports have been written to the default directory `~\.local\share\garak\garak_runs\` &#x20;

### Modules

Now, a bit about various modules in Garak. The major components are as follows:

<table data-header-hidden><thead><tr><th width="179"></th><th></th><th></th></tr></thead><tbody><tr><td><strong>Component</strong></td><td><strong>Description (2 sentences)</strong></td><td><strong>Example</strong></td></tr><tr><td><strong>Probes</strong></td><td>Probes are the <em>attackers.</em> They generate specific prompts or input scenarios to test the LLM for vulnerabilities or behavioral weaknesses. Each probe targets a particular issue like jailbreaks, injections, or bias.</td><td><code>jailbreak.JailbreakProbe</code> sends “ignore all instructions” prompts to test guardrail bypasses.</td></tr><tr><td><strong>Generators</strong></td><td>Generators are the <em>LLM interfaces</em> that Garak queries; they handle sending prompts and retrieving model responses. They abstract away API calls or local model inference.</td><td><code>ollama.OllamaGenerator</code> connects Garak to a locally running LLaMA2 via Ollama’s REST API.</td></tr><tr><td><strong>Detectors</strong></td><td>Detectors analyze model outputs to decide if a failure or unsafe behavior occurred. They can check for toxicity, leakage, or rule-breaking based on text analysis or regex.</td><td><code>toxicity.BasicDetector</code> flags model responses containing hate or violence terms.</td></tr><tr><td><strong>Evaluators</strong></td><td>Evaluators summarize and score the test outcomes, turning raw detector results into metrics or human-readable reports. They can output JSON, CSV, or formatted text.</td><td><code>basic.JSONEvaluator</code> saves a JSON file showing which probes passed or failed.</td></tr><tr><td><strong>Harnesses</strong></td><td>Harnesses control <em>how</em> tests are executed. Managing multiple probes, generators, detectors, and parallelization. They coordinate test scheduling and repeatability.</td><td><code>default.Harness</code> runs a round-robin of probes vs. detectors across chosen models.</td></tr><tr><td><strong>Resources</strong></td><td>Resources are helper files, datasets, or lookup tables used by probes, detectors, and evaluators. These can include wordlists, pattern definitions, or canned prompts.</td><td>The <code>resources/jailbreak_prompts.txt</code> file provides a base set of jailbreak prompts for testing.</td></tr></tbody></table>

By combining these, we can tailor our scans.

## 3. Connecting Garak to LLM Interfaces

## 4. Running Garak Tests

## 5. Selective Probes for Targeted Testing

## 6. Custom Prompt Sources and External Datasets

## 7. Speeding Up Scans

## 8. Understanding Garak’s Plugin Architecture

## 9. Writing Your Own Plugin

## 10. Evaluating and Reading Garak Reports

## **11. Appendix: CLI Reference and Troubleshooting**

**Headline:**\
**Quick Reference and Common Fixes**

**Main Content:**\
A concise cheatsheet for Garak’s key CLI options (`--target_type`, `--probes`, `--detectors`, `--evaluators`, `--parallel_runs`).\
Includes common issues like encoding errors, missing plugins, and REST connection fixes, with PowerShell vs. Linux equivalents.\
Perfect as a back-pocket reference when setting up new scans.

***

#### ***EVERYTHING BELOW: IGNORE***

*Generative AI Red-teaming & Assessment Kit - GARAK*

`garak` checks if an LLM can be made to fail in a way we don't want. `garak` probes for hallucination, data leakage, prompt injection, misinformation, toxicity generation, jailbreaks, and many other weaknesses. If you know `nmap` or `msf` / Metasploit Framework, garak does somewhat similar things to them, but for LLMs.

`garak` focuses on ways of making an LLM or dialog system fail. It combines static, dynamic, and adaptive probes to explore this.

Installation

Due to the intricacies of packages and to make sure our system packages don't break we'll use conda

{% embed url="<https://docs.conda.io/projects/conda/en/stable/user-guide/install/index.html>" %}

Use this to identify your env <https://repo.anaconda.com/archive/>

I'll use "[Anaconda3-2025.06-1-Linux-x86\_64.sh](https://repo.anaconda.com/archive/Anaconda3-2025.06-1-Linux-x86_64.sh)" on my Linux machine

Just install it with all default options

***

Once conda is installed, proceed with garak installation

`conda create --name garak "python>=3.10,<=3.12"`\
`conda activate garak`\
`git clone` [`https://github.com/NVIDIA/garak.git`](https://github.com/NVIDIA/garak.git)

`cd garak`\
`python -m pip install -e .`

Once installed, confirm installation with

`garak -h`

***

Now garak can connect to different LLM interfaces. Most common is the HTTP REST API endpoint that returns JSON/plaintext output.

let's assume an LLM is replying on `/api/v1/ai/chat` endpoint on a host "example.com"

Let's assume the API request looks like the following:

```http
POST /api/v1/ai/chat HTTP/1.1
Host: example.com
Cookie: Bearer AUTH TOKEN
Content-Length: 349
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36
Content-Type: application/json
Accept: */*
Origin: example.com
Accept-Encoding: gzip, deflate, br
Priority: u=1, i
Connection: keep-alive

{"datetime":"2025-09-25T19:58:25.344+00:00","domain_id":"example.com","user_id":"1","content_id":"randomcontent","item_id":"123456789","prompt":"query","question":"What is the weather in jersey"}
```

Let's assume the response body looks like:

```
HTTP/1.1 200 OK
Date: Thu, 25 Sep 2025 19:58:26 GMT
Content-Type: application/json
Content-Length: 518
Connection: keep-alive
Server: nginx
Access-Control-Allow-Methods: POST, GET, OPTIONS

{"version": "1", "response": [{"text": "### Weather in Jersey\n\nUnfortunately, the provided content does not contain information about the weather in Jersey. If you are looking for weather updates, it is recommended to check a reliable weather website or app for the most current information.", "rts": 0.8001093830025638, "logged": []}], "model": "gpt-35-turbo-16k-1106"}
```

You would manually need to create a JSON config file. You can refer to the docs here: <https://reference.garak.ai/en/latest/garak.generators.rest.html>

For our case, config becomes like:

**api\_web\_config.json**

```json
{
   "rest": {
      "RestGenerator": {
         "name": "Example Content Copilot",
         "uri": "https://example.com/api/v1/ai/chat",
         "method": "post",
         "headers": {
            "Cookie": "Bearer AUTH TOKEN",
            "Content-Type": "application/json",
	    "Accept": "*/*",
	    "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
	    "Origin": "example.com",
	    "Referer": "https://hsptpentest.latest.highspot.com/items/68d0267d9d2908070669c7de?lfrm=shp.1",
	    "Accept-Encoding": "gzip, deflate, br",
	    "Priority": "u=1, i",
            "Connection": "keep-alive"
	 },
         "req_template_json_object": {
            "datetime":"2025-09-25T15:49:27.950+00:00",
            "domain_id":"example.com",
            "user_id":"1",
            "content_id":"randomcontent",
            "item_id":"123456789",
            "prompt":"query",
            "question":"$INPUT",
         },
         "response_json": true,
         "response_json_field": "$.response[0].text",
         "skip_codes": [500,504,422],
         "request_timeout": 3000
      }
   }
}

```

Now the two main fields we need to focus in the config file above is identifying which parameter user sends their query in and which parameter does the LLM respond back in.

Here, "question" parameter in the request holds user's query and "response.text" contains LLM response

So, these two fields are specially marked in **api\_web\_config.json**

**"$INPUT"** tells garak where to inject prompts in for testing. Put this in the user controlled param for LLM query in you case.

"**response\_json\_field**" tells garak where to look for LLM response to analyze whether attack vectors worked or not. You can define the specific parameter using basic JSON object definition syntax. For example, here response is in the first field "text" encapsulated by "response" object so we defined "$.response\[0].text"

Once done you are free to run garak!

`garak --model_type rest -G api_web_config.json`

You can ploy with speed throttles as well

`garak --model_type rest -G api_web_config.json --parallel_attempts 20`

***

Test Garak

`garak --model_type test.Blank --probes test.Test`

`garak --model_type rest -G api_web_config.json --probes test.Test`

Let's say you only want specific tests like prompt injections. You can use "garak --probes" to list all the different probes

`garak --model_type rest -G api_web_config.json --probes promptinject --parallel_attempts 20`

***

**Reading the report**

```bash
# header
echo 'uuid,probe_classname,prompt.turns.content.text,outputs.text' > out.csv

# extract rows, skipping those without a valid uuid
jq -r '
  # stash id and filter: require a string uuid with length > 0
  (.uuid // .UUID) as $id
  | select($id != null and ($id | type) == "string" and ($id | length) > 0)
  | [
      $id,
      (.probe_classname // ."probe classname" // ""),
      ((.prompt.turns  // []) | map(.content?.text // "") | join(" | ")),
      ((.outputs       // []) | map(.text // (.content?.text // "")) | join(" | "))
    ]
  | @csv
' data-output-report.jsonl >> out.csv

```
