---
title: "Pre-Hooks"
slug: "prehooks"
description: "Learn how to configure and use hooks in Traceable's API Security Testing to automate authentication, test setup, and scan initialization."
updated: 2025-10-07T17:45:32Z
published: 2025-10-07T17:45:32Z
---

> ## Documentation Index
> Fetch the complete documentation index at: https://traceabledocs.document360.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Pre-Hooks

##### **Updates (October 2025 to December 2025)**

- *October 2025 —* Updated the topic to add the logger names for authentication hook testing and scan run logs.

Traceable provides the capability to write pre-hooks. The pre-hooks can be used to carry out multiple tasks, for example, authentication before starting the tests, test setup, and so on. These pre-hooks can be configured to run at multiple levels. For example, you can configure a pre-hook to run before each individual test plugin or test plugin category for the entire scan. For example, in the sample `config.yaml` file shown below, you can see that a pre-hook runs before the start of the plugin and one specific to a test. The `bfla` pre-hook shown in the sample `config.yaml` is for an individual Authorization plugin, while `crap_login_prehook` is for logging into an application. These pre-hooks are written in Python and used in Traceable CLI.

> [!NOTE]
> Note
> 
> - Pre-hooks are application-specific. Use the examples as guidance when defining your custom pre-hooks.
> - You can capture authentication hook testing logs using `logger = logging.getLogger("traceable.ast.testsuite.hookutils.simulate_hooks")`, and scan run logs using `logger = logging.getLogger("traceable.cli.scan")`.

---

## What will you learn in this topic?

By the end of this topic, you will be able to:

- Understand the use of hooks in authentication.
- Understand the concept of the crAPI credential pre-hook.
- Understand the concept of the CSRF token pre-hook.
- Understand how to configure pre-hooks.

---

### Sample user config

```yaml
# This is a sample user config. 
# Copy it to traceable config folder ~/.traceable/config.yaml to apply. 
# This config overrides data in default.yaml.
# Do not make edits to default.yaml as changes will be lost.
scan:
  plugins:
    # Enable prehooks for all plugins
    pre_hooks:
      - crapi_login_prehook
    post_hooks:
      - crapi_login_posthook
    authentication:
      unauthenticated_access:
        pre_hooks:
          # Disable crapi_login_prehook for unauthenticated_access
          - crapi_login_prehook:
              disabled: true
          # Disable crapi_login_posthook for unauthenticated_access
          - crapi_login_posthook:
              disabled: true
    authorization:
        bfla:
          pre_hooks:
            - crapi_creds_prehook
    custom:
      sample_plugin: {}
```

Make a note of the following that are used in the examples below:

- The authentication hook method is invoked before sending every request.
- You may or may not want to access the authentication endpoint before each request. You can control that behavior using `scanctx` and `pluginctx`.
- `scanctx` is a dictionary scoped per scan. To reuse any value throughout the scan, add that value with the key of your choice and use it whenever it is present. Following is an example:

Python

```python
if scanctx.get("token_key") == None:
            token = (make request to obtain token).getToken
            scanctx["token_key] = token
        token = scanctx.get("token_key")
```
- Similar to `scanctx`, `pluginctx` is scoped per plugin. So, a unique dictionary is used per plugin. You can store values at the key level.
- Hook can add key-value pairs in headers, query parameters, cookies, or the request body. You need to add these to the attributes map. For example,
  - You need to first fetch the attributes from the `testcase` (which essentially translates to the parameter of the next request) `attributes = testcase.get_attributes()`
  - To Add Cookie: `attributes.set("mutated.http.request.cookie.%s" % (cookie.name), cookie.value)`
  - To Add Header: `attributes.set("mutated.http.request.header.authorization", "Bearer fnasfjasjfoijfoiefjkewwrw") &nbsp; &nbsp;`
  - To add Query parameter: `attributes.set("mutated.http.request.query.authorization", "Bearer fnasfjasjfoijfoiefjkewwrw") &nbsp; &nbsp;&nbsp;`
  - To add body parameter: `attributes.set("mutated.http.request.body.authorization", "Bearer fnasfjasjfoijfoiefjkewwrw")`

The following two examples are two sample authentication pre-hooks for the OWASP crAPI application. For more information, see [crAPI](https://github.com/OWASP/crAPI).

## crAPI credential pre-hook

The following is a sample pre-hook function in Python:

```python
def sample_traceable_login_prehook(scanctx: ScanContext, pluginctx: PluginContext, testcase: TestCase, **kwargs) -> list[Assertion]:
    attributes = testcase.get_attributes()
    url = urllib.parse.urlparse(
        attributes.get_one("mutated.http.request.url", ""))
    logger.info("Running crapi_login_prehook for plugin %s" % pluginctx.get_plugin())
    if scanctx.get("crapi.role.user", None) is None:
        # Login:
        logger.debug("crapi_login_prehook: Token not found. Creating token")
        u = urllib.parse.urlunparse(
            url._replace(path="/identity/api/auth/login"))
        res = requests.post(u, json={
            "email": "test@example.com",
            "password": "Test!123"
        }, headers={
            "content-type": "application/json",
            "x-traceable-ast": "0,0,0"
        })
        if res.status_code != 200:
            logger.error("Failed to login to crapi, got status %d" %
                         res.status_code)
            return []

        res = res.json()
        scanctx.set("crapi.role.user", res["token"])
    else:
        logger.debug("Already logged in to CRAPI")
    attributes.set("mutated.auth.attribute", "mutated.http.request.header.authorization")
    attributes.set("mutated.role.user", "Bearer %s" % scanctx.get("crapi.role.user"))
    attributes.set("mutated.role.bolauser", "Bearer %s" % scanctx.get("crapi.role.bolauser"))
    logger.debug("Mutated role user: %s" % scanctx.get("crapi.role.user"))
    return []
```

### Explanation

This function is a pre-hook that is used to manage authentication for the [crAPI](https://github.com/OWASP/crAPI) in a security scan context.

First, the function parses the URL from the `mutated.http.request.url` attribute in the `attributes` parameter, and then checks if a token for the user's role is already present in the `scanctx` object. If not, the function logs into crAPI by sending a POST request to the login endpoint with a test email and password, and retrieves a token. The retrieved token is then stored in the `scanctx` object.

If a token is already present, the function logs a message indicating that the user is already logged in. The function then sets two attributes in the `attributes` object: `mutated.auth.attribute` is set to `mutated.http.request.header.authorization`, and `mutated.role.user` is set to "Bearer" plus the token retrieved from `scanctx`.

`scanctx` is managed by Traceable CLI internally at run time.

## CSRF token pre-hook

The following is a sample code to set the header csrf_token to a random string in an attack request. A random string can be replaced with an actual token at runtime:

```python
def set_csrf_token_prehook(scanctx: ScanContext, pluginctx: PluginContext, attributes: AttributeList) -> list[Assertion]:
    if not scanctx.get("csrf_token"):
        scanctx.set("csrf_token", "".join(random.sample(string.ascii_lowercase, k=10)))
    attributes.set("mutated.http.request.header.csrf_token", scanctx.get("csrf_token"))
    return []
```

#### Explanation

The function checks if a CSRF token is already present in the `scanctx` object by attempting to retrieve it using the `get()` method with the key `"csrf_token"`. If a CSRF token is not present, the function generates a new CSRF token by randomly selecting 10 characters from the lowercase English alphabet using the `random.sample()` method and stores it in the `scanctx` object with the same key `"csrf_token"`.

The function then sets the `mutated.http.request.header.crf_token` attribute in the `attributes` object to the CSRF token retrieved from `scanctx` using the `get()` method with the same key `"csrf_token"`.

---

## Configuring the pre-hook

The pre-hooks that you create need to be configured in Traceable CLI. Make sure that Traceable CLI is installed before proceeding. The important files and directories in Traceable CLI that are used for pre-hooks are:

- hooks directory – Your pre-hooks and post-hooks are stored in this directory.
- `config.yaml`
- `default.yaml`

The `default.yaml` file is provided by Traceable. Whatever is added to default.yaml is overwritten by config.yaml. It is a practical approach to have your working pre-hooks configured in`&nbsp;config.yaml`. The `config.yaml` file is given preference at run time. Refer to the `config.yaml` listed at the start of the topic.

## Related

- [Plugins](/test-custom-plugin.md)
