Back to Logbook
May 19, 2026 Project: #Portfolio

Security day. The first hard one.

intense

This was the biggest day so far. Took a security audit of the codebase and found seven serious issues. Fixed all of them in the same session.

The worst one was command injection in AutomationEngine — it was executing spark commands stored in the database via exec() with no sanitization. Wrote sanitizeSparkCommand() to strip metacharacters and added escapeshellarg() on every call. Then went through the file upload paths in Admin/Settings (logo, dark logo, favicon, OG image) and added MIME-type allowlist validation everywhere — extension alone was not enough. Added rate limiting on the contact form (5 submissions per 10 minutes per IP).

While I was in there: fixed a silent bug where getMethod() === 'post' always failed in CI4 4.x because the method now returns uppercase 'POST' — the contact form had been falling through to the GET branch in production without anyone noticing.

Migration housekeeping: replaced MySQL-only SHOW TABLES/SHOW COLUMNS calls in one migration with driver-agnostic tableExists()/fieldExists() — that single change fixed 10 failing SQLite tests. Also went through 27 createTable migrations and added PRIMARY KEY to columns that had AUTO_INCREMENT without it.

Test suite went from 10 errors to 29/29 passing. Then the infrastructure work: wrote .github/workflows/ci.yml, generated phpstan-baseline.neon, git init, first commit, committed vendor/ for shared hosting deployment.

Long day. The codebase is now in a much more defensible state.

Lessons Learned

A 30-minute audit can save weeks of cleanup. Schedule them.