Skip to content

Security Audit

DatumApril 2026
Scope53 PHP bestanden in werkbon thema
ErnstAantal
Kritiek1
Hoog4
Medium4
Laag2

Ernst: KRITIEK Bestanden: api-contact.php:392, api-job.php:25, api-file.php:289

function acs_permission_contacts(): bool {
return true; // GEEN AUTH CHECK
}

Alle 3 API bestanden:

// api-contact.php:391
function acs_permission_contacts(): bool {
return true; // return is_user_logged_in() && current_user_can('edit_posts');
}
// api-job.php:25
function acs_job_api_permission(): bool {
return true;
}
// api-file.php:289
'permission_callback' => '__return_true',

Reproductie:

Terminal window
# Dump alle contacten met persoonsgegevens
curl -s 'https://werkbon.nl/wp-json/acs/v1/contacts?per_page=100' | jq '.items | length'
# Maak ongeautoriseerd een melding aan
curl -X POST 'https://werkbon.nl/wp-json/acs/v1/jobs/create' \
-H 'Content-Type: application/json' \
-d '{"description":"test","email":"test@test.nl"}'

Impact:

  • GET /wp-json/acs/v1/contacts dumpt alle persoonsgegevens (namen, emails, telefoons, adressen)
  • POST /wp-json/acs/v1/contacts/upsert — iedereen kan contacten wijzigen
  • POST /wp-json/acs/v1/jobs/create — iedereen kan meldingen aanmaken
  • AVG/GDPR overtreding — Artikel 32 (beveiliging), Artikel 5 lid 1f (integriteit en vertrouwelijkheid)

Aanbeveling:

function acs_permission_contacts(): bool {
$secret = $_SERVER['HTTP_X_ACS_SECRET'] ?? '';
if ($secret && hash_equals(WERKBON_API_SECRET, $secret)) return true;
return is_user_logged_in() && current_user_can('edit_posts');
}

Geschatte tijd: 1 uur

Bestanden: show-reports.php:725, show-jobs.php:558

$query_args = $_GET; // ONGESANITEERD

XSS vector via geinjecteerde query parameters. Fix: whitelist + sanitize_text_field().

Geschatte tijd: 30 min

Bestanden: show-reports.php:81, show-jobs.php:105, show-dashboard.php:45-53

<a href="<?php echo get_the_permalink(2); ?>">

Moet: esc_url(get_the_permalink(2))

Geschatte tijd: 15 min

Bestand: functions.php:4

error_log('LOADED FUNCTIONS: ' . __FILE__);

Bij elke pageload. Log flooding + informatie disclosure.

Geschatte tijd: 5 min

FINDING-05: AJAX missing explicit login check

Section titled “FINDING-05: AJAX missing explicit login check”

Bestand: modal-jobs.php:178

update_job_status mist expliciete is_user_logged_in() check. Impliciet via current_user_can maar inconsistent met delete_job handler.

Geschatte tijd: 5 min

FINDING-06: ABSPATH guard ontbreekt (43/53 bestanden)

Section titled “FINDING-06: ABSPATH guard ontbreekt (43/53 bestanden)”

43 van 53 PHP bestanden missen if (!defined('ABSPATH')) exit;. Directe toegang kan pad-informatie lekken via PHP errors.

Geschatte tijd: 30 min

Section titled “FINDING-07: Sessie cookie 30 dagen zonder Remember Me”

Bestand: login.php:44

$remember parameter wordt genegeerd. Op gedeelde apparaten onverwacht lang actief.

Geschatte tijd: 10 min

Bestanden: api-file.php:13, api-contact.php:10

Make.com webhook URLs met tokens hardcoded en in Git.

Geschatte tijd: 30 min

Bestanden: navigation.php:38, show-login.php:7

file_get_contents() op SVG zonder sanitatie. SVGs kunnen <script> tags bevatten.

Geschatte tijd: 15 min

Bestand: functions.php:7

Elk bestand in /functions/ wordt auto-executed. Risico bij schrijftoegang.

Bestand: form-addresses.php:41

Address lookup voor niet-ingelogde gebruikers. Data niet gevoelig maar onnodige exposure.

Ernst: LAAG Bestand: form-prefill.php

Form prefill parameters (?job_id=123, ?wpf40_58=123, ?wpf40_74=maasdelta) worden zonder nonce-verificatie gelezen uit $_GET. Een aanvaller kan een URL crafting die het formulier voorvult met specifieke waarden.

Impact: Laag — de monteur moet het formulier nog steeds zelf submitten. Maar het kan misleidend zijn als de prefill waarden onverwacht zijn.

Reproductie:

https://werkbon.nl/werkbon-invullen/?wpf40_74=maasdelta&wpf40_68=Fake+Company

Bij migratie naar de Beam stack (Supabase + Hono API) worden de volgende findings automatisch opgelost:

FindingOpgelost doorReden
FINDING-01 (open API)Hono auth middlewareBearer token vereist op alle routes
FINDING-02 (raw $_GET)React RouterGeen server-side URL building
FINDING-03 (unescaped permalink)React JSXAutomatische escaping
FINDING-04 (debug logging)Geen functions.phpStructured logging via middleware
FINDING-06 (ABSPATH guard)Geen PHP bestandenTypeScript modules
FINDING-07 (sessie 30d)Supabase AuthConfigureerbare sessie duur
FINDING-08 (webhook secrets)Wrangler secretsEnvironment variables, niet in code
FINDING-09 (raw SVG)React componentsGeen file_get_contents
FINDING-10 (glob include)ES modulesExpliciete imports
FINDING-11 (nopriv AJAX)Auth middlewareAlle routes geauthenticeerd
FINDING-12 (CSRF prefill)React stateGeen URL-gebaseerde prefill

Zie Migratie naar Beam Stack voor de volledige migratie analyse.

FindingWaarschijnlijkheidImpactRisico
F-01: Open APIHoog (publiek bereikbaar)Kritiek (PII exposure)Kritiek
F-02: Raw $_GETMedium (vereist crafted URL)Hoog (XSS)Hoog
F-03: Unescaped permalinkLaag (vereist admin compromise)Medium (XSS)Medium
F-04: Debug loggingHoog (elke pageload)Laag (info disclosure)Medium
F-05: Missing login checkLaag (impliciet beschermd)Medium (privilege escalation)Laag
F-06: ABSPATH guardsLaag (vereist directe URL)Laag (path disclosure)Laag
F-07: 30d sessieHoog (altijd actief)Medium (session hijacking)Medium
F-08: Webhook secretsMedium (repo access nodig)Hoog (webhook abuse)Hoog
F-09: Raw SVGLaag (vereist fs access)Medium (XSS)Laag
F-10: Glob includeLaag (vereist fs access)Hoog (RCE)Medium
F-11: nopriv AJAXHoog (publiek)Laag (publieke data)Laag
F-12: CSRF prefillHoog (publiek)Laag (misleiding)Laag
VereisteStatusFinding
Art. 5(1)(f) — Integriteit en vertrouwelijkheidNiet voldaanF-01
Art. 25 — Data protection by designNiet voldaanF-01
Art. 32 — Beveiliging van verwerkingNiet voldaanF-01, F-08
Art. 33 — Melding datalek aan APN.v.t.Geen actief lek bekend
Art. 35 — DPIA (Data Protection Impact Assessment)Niet uitgevoerdAanbevolen
CategorieStatusFinding
A01: Broken Access ControlNiet voldaanF-01
A02: Cryptographic FailuresVoldaan
A03: Injection (SQL)Voldaan$wpdb->prepare()
A04: Insecure DesignDeelsF-07, F-10
A05: Security MisconfigurationDeelsF-04, F-06
A06: Vulnerable ComponentsOnbekendDependencies niet geaudit
A07: Auth FailuresDeelsF-01, F-05
A08: Data Integrity FailuresVoldaanNonces op forms
A09: Logging FailuresDeelsF-04 (overmatig)
A10: SSRFVoldaanGeen user-controlled URLs
AspectStatus
Input sanitization ($_GET)Goed — sanitize_text_field(), absint(), in_array()
SQL injection ($wpdb->prepare)Goed — consistent gebruikt
AJAX nonce verificatieGoed — check_ajax_referer()
Admin form beschermingGoed — wp_nonce_field + check_admin_referer
Output escaping (templates)Goed — esc_attr(), esc_html()
Capability checksGoed — current_user_can()
Geen eval/unserializeGoed
#BevindingErnstTijd
1REST API authenticatieKritiek1 uur
2$_GET whitelist paginationHoog30 min
3Webhook secrets naar envMedium30 min
4Permalink escapingHoog15 min
5Debug logging verwijderenHoog5 min
630-dagen sessie fixenMedium10 min
7ABSPATH guardsMedium30 min
8SVG sanitatieMedium15 min
9Glob include filterLaag10 min
10nopriv AJAX verwijderenLaag5 min