g3rt.com

Offensive

Nonprofit Site: Audit, Remediation, Rebuild

Found the hole, fixed it, then made the site theirs to run.

  • WordPress
  • PHP
  • OWASP
  • WPScan
  • Accessibility

Note:Client details are withheld under the terms of the engagement. The technical findings below are reproduced in full.

releases delivered
27
page templates
19
stored XSS found & fixed
1
upstream files modified
0

A nonprofit early-childhood center engaged me to review their public site. The audit was the starting point, not the deliverable. A findings report they had no way to act on would have left them exactly where they began.

The audit covered WordPress core, 16 plugins, and a custom theme, cross-checked against Wordfence Intelligence, WPScan, Patchstack, the GitHub Advisory Database, and NVD.

The significant finding was a stored XSS path in the parent theme: it registered contact and social customizer settings with no sanitize_callback, then echoed them unescaped straight into href attributes. Anyone with customizer access could persist script into every page.

The fix mattered as much as the finding. Rather than patching the parent theme which the next update would have silently reverted. Remediation went into a child theme via theme_mod_{$name} filters applying esc_url, sanitize_email, and sanitize_text_field. Zero upstream files touched, so the site stays updatable and the fix survives.

That child theme became the rest of the engagement. Nineteen page templates and roughly 2,400 lines of PHP across 27 releases: a rebuilt homepage, per-program pages, staff and team pages, a tour-booking page, and a subsidy-program page for families who needed one.

The design constraint that shaped everything: the office had to be able to run it. Every photo, testimonial, rate table and menu is a Customizer field, so staff update the site through the WordPress admin and never touch code or call me. Empty slots simply do not render, which means the site degrades to less content rather than to broken layout. No placeholder can reach production.

Some of that governance is enforced in the templates rather than trusted to process. The testimonials carousel stays hidden until a real quote is entered, so no lorem-ipsum review can ship. An optional per-testimonial toggle renders a two-word name as "First L." there for when a parent agrees to be quoted but not identified.

One release was purely the director's feedback: schedule formats made consistent, tuition tables clarified with billing cadence, financial assistance surfaced on the page instead of buried in the footer, and a dead social link removed. Their brand typeface is named in the CSS stack with a graceful fallback rather than embedded, because naming a font needs no licence and embedding one does.

Details