TasteLocal: A Practical VAPT Checklist for Clojure and HTMX
I used to think a vulnerability assessment needed a giant report before it could be useful. Then I started treating the application as a set of small, testable boundaries instead of a ceremony.
This rewrite applies that approach to TasteLocal, a hyper-local culinary discovery platform with search, bookings, reviews, itineraries, and role-based dashboards. The public deployment is available at lithan.nurazhar.com.
The goal is not to claim that a short review replaces a formal penetration test. The goal is to show how a focused checklist makes the important security questions visible early.
🧭 The Application Surface
TasteLocal keeps its runtime deliberately focused:
- Frontend: Server-rendered HTML with HTMX for dynamic interactions, reducing the amount of client-side state to audit.
- Backend: Clojure/Babashka using Ring and HTTP Kit for the request and session boundary.
- Database: Embedded SQLite for a simple local mode, with PostgreSQL support for a production-style deployment.
- Deployment: A Dockerized application running on Northflank.
The platform exposes different workflows for Tourist/Foodie, Vendor/Business, and Admin users. That makes authorization—not just input validation—the central assessment concern.
🔍 The VAPT Checklist
A lean stack is easier to reason about, but it is not automatically secure. These are the checks that matter most for TasteLocal’s architecture.
1. HTML Injection at the HTMX Boundary
HTMX responses often contain HTML fragments assembled from database values such as restaurant names, reviews, or vendor descriptions.
- Check: Trace every user-controlled value from the request through persistence and into a response fragment.
- Control: Escape output at the rendering boundary and verify that markup supplied as data cannot become executable HTML.
- Test: Submit harmless HTML-shaped strings through every form, then inspect both the full page and partial HTMX responses.
2. Role-Based Access Control
A hidden button is not an authorization control. The server must enforce the role attached to the authenticated session on every restricted action.
- Check: Exercise the same route as Tourist/Foodie, Vendor/Business, and Admin users.
- Control: Enforce authorization in Ring middleware or the handler boundary before changing bookings, vendor records, reviews, or administrative settings.
- Test: Replay restricted
GETandPOSTrequests with a valid session belonging to the wrong role and expect a deliberate403response.
3. Session and Authentication Handling
Session-based applications need a clear boundary around cookies, login transitions, and logout behavior.
- Check: Confirm that session cookies use secure deployment attributes, expire predictably, and are invalidated on logout.
- Control: Keep password verification and session signing secrets in runtime configuration rather than source files.
- Test: Try session reuse after logout, privilege changes, and login failures; verify that errors do not disclose account or implementation details.
4. Database Queries and Business Rules
Bookings, reviews, and itineraries are relational data with rules that should not depend on browser behavior.
- Check: Review every query that accepts search terms, identifiers, or form values for parameter binding rather than string concatenation.
- Control: Enforce database constraints for impossible states, such as invalid booking quantities or references to missing records.
- Test: Send boundary values, malformed identifiers, and repeated submissions through both the normal UI and direct requests.
📦 Deployment and Secret Hygiene
The public repository makes the application easier to inspect, which also makes accidental configuration exposure easier to spot. Docker and Northflank should receive database credentials, session secrets, and other environment-specific values at runtime.
The repository should contain configuration shape, not production credentials. A clean deployment review checks container configuration, environment-variable names, debug settings, logs, and error responses together.
The public source is available in the lithan-capstone-project repository, while the running application is available at lithan.nurazhar.com.
💡 The Security Lesson
A small architecture does not remove the need for VAPT. It gives the reviewer fewer boundaries to understand and fewer places for security assumptions to hide.
The practical win is feedback velocity: test the session boundary, the HTMX rendering boundary, the authorization boundary, and the database boundary before a vague report turns into a backlog.
TasteLocal is a useful example of that principle: keep the runtime understandable, make each role explicit, and turn every trust boundary into a repeatable test.