Curriculum vitae · Nairobi, Kenya
Paul MK
Software engineer · Application security
Available now — full-time roles and short engagements. Backend, platform and DevSecOps roles, and multi-tenant authorization and payment integration reviews.
Remote, or on-site in Nairobi · UTC+3 — full overlap with UK and EU hours, mornings only with the US west coast
| paulmk2143@gmail.com | |
| Site | paulappsec-site.paulmk2143.workers.dev |
| GitHub | github.com/PaulAppSec |
| linkedin.com/in/paulappsec | |
| Writing | paulappsec.hashnode.dev |
Summary
Self-taught software engineer. I build production multi-tenant and payment systems, then attack them across tenant boundaries, webhooks and authorization paths — the same skill applied from both directions, which is the combination most application security work actually asks for.
Sole engineer on a commercial parking platform of roughly 36,000 lines across a Python API and a Go edge agent, covering plate capture, mobile-money settlement, physical barrier control and multi-tenant isolation — one of four operational systems I have built, totalling ~120,000 lines. Publish a tested Semgrep rule pack, and a regression harness of 24 bug classes proven in both directions by 48 tests: one asserting each bug is live, one asserting each remediation holds.
Selected work
Each one is public, or its verification state isA commercial parking platform: cameras read plates at the gate, an on-site Go agent runs the lane through network loss, drivers pay by M-Pesa on exit straight to the operator’s own till, and a barrier opens on a dry contact. Multi-tenant, with an operator console, an admin console, guard and driver apps, permits, enforcement, reconciliation and subscription billing. Roughly 36,000 lines, built solo.
Python · FastAPI · SQLAlchemy async · PostgreSQL/TimescaleDB · Go · React/TS · Docker
A regression harness for 24 web vulnerability classes. Each class is proven in both directions by code: an exploit test that expects the attack to succeed on main, and a fixed test that reuses the same attack code and expects it to be refused on the class’s fix branch. 48 tests in two suites.
TypeScript · Node/Express · Prisma · Docker
Custom JS/TS rules for unscoped lookups, mass assignment, path traversal and fail-open error handling, grouped by OWASP category with a test fixture sitting beside every rule.
YAML · Semgrep · JS fixtures · GitHub Actions
Stack, and where each part is proven
Check any of it →| Language | Where it is used | Evidence |
|---|---|---|
| Python | ParkSense API — FastAPI, SQLAlchemy async, Alembic | 196 files · ~29,700 lines · 486 passing tests |
| Go | ParkSense edge agent — offline queue, RTSP capture, TCP ingest, relay watchdog | 37 files · ~6,200 lines · build and vet clean |
| TypeScript | Kartly — Node, Express, Prisma. Also the ParkSense React consoles. | 128 files · ~4,100 lines · 48 tests proving 24 bug classes both ways |
| SQL | PostgreSQL and TimescaleDB — the ParkSense schema and its migrations | 19 migrations, single head, round-trip verified |
| Semgrep / YAML | A published rule pack for the bug classes I keep finding | 4 rules · 4 fixtures · tested in CI on every push |
| Astro / CSS | This site — no framework, no client JavaScript, one external stylesheet | 16 pages and components · 0 KB of JavaScript shipped |
Writing
This site, as an artifact
Built with Astro and no client-side JavaScript, behind a Content Security Policy ofdefault-src 'none'; script-src 'none'. The grades below were awarded by third-party scanners against the live origin, and every claim on this site has a command you can run to check it.
securityheaders.com
A+
Mozilla Observatory
A+
JS shipped
0 KB