Skip to main content

Post-processing with Hooks


In this step-by-step tutorial, we will go through all the required stages to set up Hooks with the secureCodeBox. Hooks can be used to perform post-processing on findings, for which we'll give a few examples.


For the sake of the tutorial, we assume that you have your Kubernetes cluster already up and running and that we can work in your default namespace. If not, check out the installation for more information.

We'll start by installing the nmap scanner:

$ helm upgrade --install nmap secureCodeBox/nmap

Next, we'll install two update-field hooks:

$ helm upgrade --install ufh1 secureCodeBox/update-field-hook --set"category" --set attribute.value="first-hook"$ helm upgrade --install ufh2 secureCodeBox/update-field-hook --set"category" --set attribute.value="second-hook"

The first hook will update all secureCodeBox findings such that the field category is set to the value first-hook. The second hook will set the same field to second-hook. For a list of all available secureCodeBox hooks, see hooks. There's no limit to the amount of hooks you can install.

Creating a scan#

In practice, you are not required to specify anything to run your hooks.

apiVersion: ""kind: Scanmetadata:  name: "nmap-example"spec:  scanType: "nmap"  parameters:    # We'll just scan for port 80 to speed up the scan.    - "-p"    - "80"    # Scanning an example domain    - ""

For starting scans in Kubernetes, see First Scans.

Once the scan has finished, you will see that two hooks have run on your scan results.

$ kubectl get podsNAME                                                 READY   STATUS      RESTARTS   AGEparse-nmap-example-5p964--1-ctgrv                    0/1     Completed   0          18sscan-nmap-example-gg9kd--1-pjltd                     0/2     Completed   0          26sufh1-update-field-hook-nmap-example-p8pcb--1-vx25q   0/1     Completed   0          10sufh2-update-field-hook-nmap-example-drjmq--1-vzds2   0/1     Completed   0          3s 

Inspecting the findings#

Looking at the findings, you will notice that the category field has been set to second-hook. This happens because the ufh2 hook was executed after ufh1, discarding the value first-hook completely.

[  {    "name": "Open Port: 80 (http)",    "description": "Port 80 is open using tcp protocol.",    "category": "second-hook",    "location": "tcp://",    "osi_layer": "NETWORK",    "severity": "INFORMATIONAL",    "attributes": {      ...    },    "id": "9fbda429-478d-4ce0-9a8d-1c4aef4d9b58"  }]

Hook order#

By default, hook order is specified according this definition.

With the hook.priority field, you can further customize the order of secureCodeBox hooks. The higher the priority of a hook, the earlier it will execute. By default, all hooks have a priority of 0.

If we set ufh2 hook's priority to 1, we'll observe that it will execute before ufh1.

$ helm upgrade --install ufh2 secureCodeBox/update-field-hook --set hook.priority="1" --set"category" --set attribute.value="second-hook"
$ kubectl get scancompletionhooks.execution.securecodebox.ioNAME                     TYPE           PRIORITY   IMAGEufh1-update-field-hook   ReadAndWrite   0   ReadAndWrite   1  

Start, the scan and observe orders:

$ kubectl get pods                                                                                                kube minikubeNAME                                                 READY   STATUS      RESTARTS   AGEparse-nmap-example-lrtcl--1-57n9t                    0/1     Completed   0          36sscan-nmap-example-7s2t8--1-gbr6b                     0/2     Completed   0          39sufh1-update-field-hook-nmap-example-cvzw2--1-x4rcz   0/1     Completed   0          30sufh2-update-field-hook-nmap-example-mv57q--1-cvd4k   0/1     Completed   0          33s

Kubernetes sorts the list alphabetically, but notice the age of the jobs. Looking at the resulting finding, we can see the category is set to first-hook.

[  {    "name": "Open Port: 80 (http)",    "description": "Port 80 is open using tcp protocol.",    "category": "first-hook",    "location": "tcp://",    "osi_layer": "NETWORK",    "severity": "INFORMATIONAL",    "attributes": {      ...    },    "id": "c15d1730-7ca8-4529-b55a-a3412832f309"  }]

Hook selector#

An alternative for more runtime hook control is the scan's HookSelector. This field allows you to define which hooks to run for a scan.

In this case, we select all hooks, except hooks with the label ufh1.

apiVersion: ""kind: Scanmetadata:  name: "nmap-example"spec:  hookSelector:    matchExpressions:    - key:      operator: NotIn      values: [ "ufh1" ]  scanType: "nmap"  parameters:    # We'll just scan for port 80 to speed up the scan.    - "-p"    - "80"    # Scanning an example domain    - ""

You can find that only ufh2 was executed.

$ kubectl get pods                                                                                                                                                           kube minikubeNAME                                                 READY   STATUS      RESTARTS   AGEparse-nmap-example-shkrr--1-2hdt9                    0/1     Completed   0          10sscan-nmap-example-7bllp--1-zx287                     0/2     Completed   0          13sufh2-update-field-hook-nmap-example-lmljv--1-smgp5   0/1     Completed   0          7s

The following labels are available by default:

  • the Helm release name (e.g. ufh1, ufh2)
  • the Helm chart name (e.g. update-field-hook)
  • boolean field for whether this hook has internal usages in secureCodeBox (e.g. Cascading Scans hook)

You can also deploy secureCodeBox hooks with your own labels like so:

$ helm upgrade --install ufh2 secureCodeBox/update-field-hook --set hook.labels.securecodebox="rocks" --set"category" --set attribute.value="second-hook"

This will add your custom label to the secureCodeBox hook so that you can select is with hookSelector.

apiVersion: ScanCompletionHookmetadata:  labels: ufh2 Helm update-field-hook update-field-hook-3.3.1    securecodebox: rocks  name: ufh2-update-field-hook  namespace: defaultspec:  env:  - name: ATTRIBUTE_NAME    value: category  - name: ATTRIBUTE_VALUE    value: second-hook  image:  ttlSecondsAfterFinished: null  type: ReadAndWrite

Cascading scans#

The HookSelector field is also available in Cascading Rules. This means that you can selectively disable hooks for certain rules. Let's say that you're running secureCodeBox with nmap, ncrack, and a DefectDojo persistence provider. We can imagine that you'd prefer your ncrack passwords to not go directly to DefectDojo, so you could set up the cascading rule such that it filters the DefectDojo hook.

apiVersion: ""kind: CascadingRulemetadata:  name: "ncrack-ftp"  labels: invasive high bruteforcespec:  matches:    anyOf:      - category: "Open Port"        attributes:          service: "ftp"          state: open  scanSpec:    hookSelector:      matchExpressions:      - key:        operator: NotIn        values: [ "persistence-defectdojo" ]    scanType: "ncrack"    parameters:      - -v      - -d10      - -U      - /ncrack/users.txt      - -P      - /ncrack/passwords.txt      - -p       - ftp:{{attributes.port}}      - "{{$.hostOrIP}}"

Note that we use here to filter all releases of the DefectDojo persistence provider.


You can use scan.spec.cascading.inheritHookSelector on your initial scan definition to pass hookSelector entries on to cascaded scans. Selectors defined in cascading rules will only apply to the scan triggered by the rule - if the results of that scan then trigger further cascading scans, the selectors defined in the cascading rule will be dropped and only those from the original scan are kept. Defining identical entries in both the Scan AND the Cascading Rule resource will lead to undefined behaviour. See #789 for more details.