WordPress vulnerability scans afhandelen met n8n

wp scan bloga

WordPress-installaties vormen een aantrekkelijk doelwit voor misbruik, zeker wanneer kwetsbare plugins of thema’s niet tijdig worden gesignaleerd. Tegelijkertijd wil je voorkomen dat dagelijkse security-scans leiden tot ruis, onnodige logging of overbodige alerts. In dit artikel beschrijven we hoe je met een self-hosted n8n-workflow en de WPScan-plugin een robuuste, schaalbare en efficiënte afhandeling van WordPress vulnerability alerts kunt inrichten.

Alleen bij daadwerkelijke onraad wordt de scan informatie opgeslagen in de database en gelogd; bij een schone scan is een korte informatieve melding in het logbestand voldoende.

Architectuur op hoofdlijnen

De oplossing bestaat uit vier logisch gescheiden componenten:

  1. WPScan plugin (WordPress)
    • Draait periodiek (bijvoorbeeld dagelijks).

    • Stuurt scanresultaten via een webhook als JSON naar n8n.

    • Beperking: maximaal twee scans per etmaal (plugin-afhankelijk).

  2. n8n Webhook
    • Ontvangt de scanresultaten.

    • Vormt het startpunt van de workflow.

  3. Normalisatie en filtering (Code-node)
    • Extraheert vulnerabilities uit plugins, themes, WordPress core en security checks.

    • Zet deze om naar een uniform datamodel.

    • Voegt één expliciet log-item toe voor beslislogica.

  4. Conditionele verwerking
    • Alleen daadwerkelijke vulnerabilities worden opgeslagen in PostgreSQL.

    • Logging (INFO of WAARSCHUWING) gebeurt op basis van één samenvattend log-item.

Normaliseren van vulnerability scans vóór beslissen

Een belangrijke ontwerpkeuze is het normaliseren van de webhook-payload voordat er beslissingen worden genomen. WPScan levert zijn resultaten namelijk genest aan, bijvoorbeeld:

  • plugins → vulnerabilities

  • themes → vulnerabilities

  • wordpress core → vulnerabilities

  • security-checks → vulnerabilities

In plaats van deze structuur downstream te blijven interpreteren, is in n8n gekozen voor één centrale Code-node die:

  • alle vulnerabilities verzamelt;

  • per vulnerability één database-record oplevert;

  • exact één extra item toevoegt met samenvattende informatie.

Dat log-item ziet er conceptueel als volgt uit:

{
"is_log_item": true,
"has_vulnerabilities": true,
"vulnerability_count": 1
}

Dit patroon heeft twee voordelen:

  • downstream nodes hoeven niets te weten van de oorspronkelijke WPScan-structuur;

  • de beslislogica is eenvoudig en makkelijker controleerbaar in de workflow.

Opslag in PostgreSQL: alleen wat ertoe doet

De PostgreSQL-tabel wp_scan_logs bevat uitsluitend relevante security-events, geen lege of “schone” scans. De tabelstructuur is bewust compact gehouden:

kolombetekenis
scan_datetijdstip van detectie
vulnerability_typetype kwetsbaarheid
severityernst (indien beschikbaar)
plugin_themeplugin, theme of core
versionbetrokken versie
detailskorte toelichting

Hiermee ontstaat een historisch overzicht dat geschikt is voor analyse en dat eenvoudig te koppelen is aan dashboards of meldingen.

Logging: één regel per scan, niet per plugin

Een veelgemaakte valkuil bij security-scans is over-logging. In deze workflow is dat expliciet voorkomen.

De beslislogica in de IF-node kijkt uitsluitend naar het log-item:

  • Vulnerability gevonden
    [WAARSCHUWING] WP scan uitgevoerd. Eén of meerdere vulnerabilities gevonden.

  • Geen vulnerabilities
    [INFO] WP scan uitgevoerd. Geen vulnerabilities gedetecteerd.

De true/false-branches van de IF-node zijn zodanig ingericht dat de true branch leidt tot een INFO melding en de false branch tot een WAARSCHUWING melding. De IF-node wordt bovendien slechts één keer geëvalueerd (op het log-item), en dus niet op elk vulnerability-record. Het resultaat is een logbestand met maximaal één regel per scan.

Eén ding heeft me beziggehouden nadat de n8n workflow goed bleek te werken ‘in productie’.

Waarom lopen in n8n soms zowel de TRUE- als de FALSE-branch van een IF-node?

Een belangrijk inzicht bij het werken met n8n is dat IF-nodes per item worden geëvalueerd, niet per workflow-run. Dit is wezenlijk anders dan hoe ik zou redeneren over “één scan” of “één gebeurtenis”.

In deze workflow produceert de Code-node bewust meerdere items:

  • één item per gevonden vulnerability (bijvoorbeeld een kwetsbare plugin);

  • één extra item dat fungeert als log-item, met daarin samenvattende informatie zoals:

    • has_vulnerabilities

    • vulnerability_count.

Wanneer deze items door een IF-node gaan, beoordeelt n8n elk item afzonderlijk tegen de ingestelde conditie. In het geval van de conditie:

{{$json.is_log_item !== true}}

gebeurt het volgende:

  • vulnerability-items hebben géén is_log_item → dus false → de conditie is waar (immers de waarheid wordt omgekeerd geëvalueerd ‘!==’) → TRUE-branch;

  • het log-item heeft is_log_item === true → dus true → de conditie is onwaar (immers de waarheid wordt omgekeerd geëvalueerd ‘!==’) → FALSE-branch.

Het resultaat is dat beide branches actief lijken, terwijl in werkelijkheid elk item precies één branch volgt. Er is dus geen fout in de IF-node en geen dubbele verwerking van hetzelfde object.

Dit item-gebaseerde uitvoeringsmodel is een kenmerk van n8n en maakt het mogelijk om:

  • individuele vulnerabilities op te slaan in een database;

  • tegelijkertijd éénmalige logging of alertering uit te voeren op basis van het totale scanresultaat.

Met behulp van taalmodellen heb ik dit conditionele patroon als code toegepast. Hiermee worden alleen de relevante data opgeslagen en alleen bij echte onraad zoals ik het maar noem, wordt gelogd of gewaarschuwd.

Leerpunten

Deze implementatie was er eentje van trial-and-error….

  1. Normaliseer vroeg. Beslislogica werkt alleen betrouwbaar als de input eenduidig is.

  2. Scheid data van beslissingen. Vulnerability-records en logica-items hebben verschillende doelen en moeten dat ook expliciet uitdrukken.

  3. Ga uit van beperkingen van tooling. WPScan-rate-limits betekenen dat “lege” payloads valide zijn; de workflow moet daar expliciet tegen bestand zijn.

  4. Minimaliseer ruis. Security-monitoring is alleen effectief als signalen schaars en betekenisvol zijn.

Resultaat

Met deze opzet ontstaat een workflow die dagelijks automatisch draait en alleen de relevante security-informatie opslaat. Deze is makkelijk te inspecteren omdat er geen uitgebreide logs zijn en bovendien wordt de database alleen geactualiseerd wanneer er vulnerability informatie is.

Geef een reactie

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *