Security
Controls implemented in this sandbox, against the regimes named in RFQ Submission Requirement 10: T&T data protection legislation, PCI DSS, and TT-CSIRT security review. Everything below is verifiable from the running application — check the response headers.
Implemented
| Content-Security-Policy | default-src 'self'. No third-party origin may supply script, style, font, or frame content. Inline scripts run only with a per-request nonce. |
| No third-party scripts | Tailwind is compiled to a static stylesheet; Alpine, Lucide and Leaflet are served from this origin; web fonts are self-hosted. The application loads no CDN. |
| Transport | HTTPS enforced by redirect, HSTS for one year including subdomains, and the session cookie marked Secure whenever the browser leg is encrypted — including behind a TLS-terminating proxy. |
| Session | HttpOnly and SameSite=Lax session cookie; server-side session state. |
| CSRF | A masked synchroniser token is required on every state-changing request. Requests without it are rejected with 422. |
| Authorisation | Role guards run as middleware on route groups, before any controller executes. |
| Publication gate | An unverified vendor cannot publish a product. The rule is enforced in the repository layer, so it holds regardless of what the request asks for. |
| Passwords | Stored as bcrypt hashes via PHP's password_hash. Never logged, never returned. |
| Input handling | Typed form models with declared validation rules; all database access through bound parameters. |
| Other headers | X-Content-Type-Options, X-Frame-Options DENY, Referrer-Policy, Permissions-Policy, and cross-origin isolation headers. The PHP version banner is removed. |
| Security logging | Sign-in success and failure, sign-out, authorisation denials, vendor status changes, and blocked publication attempts are logged with account, route, and IP. |
| Recommendations | Similarity is a term-frequency vector model computed on this server. No external service is called and no product data leaves the origin. Ranking weightings are set by the operator, not fixed by the supplier. |
| Walkthrough forms | The design-walkthrough screens accept input and carry it through a journey, held in your own session only. Nothing entered there is written to the database or visible to anyone else. The functional flows — registration, catalogue, cart, checkout, vendor and administrator tools — are real and stored in MySQL. |
Stated exceptions
Four concessions, named here rather than left for a reviewer to find.
-
’unsafe-eval’ on the design-walkthrough screens.
Alpine.js compiles expressions with
new Function(). The eighteen walkthrough screens that use it request the exception individually; the commerce flows — cart, checkout, product, vendor and administrator pages — run under the strict policy with no eval. The delivered platform uses Alpine’s CSP-safe build and drops the exception. -
’unsafe-inline’ for style.
The screens use inline
styleattributes throughout. Inline style cannot execute, so the risk is presentational rather than code execution. - Two remote image origins. Product photography from Unsplash and map tiles from OpenStreetMap. Images do not execute, but the requests disclose a visitor’s IP address to those providers — a cross-border disclosure under the twelfth privacy principle. The delivered platform serves both from its own CDN.
- The similarity model matches shared words, not meaning. It will not relate "pepper sauce" to "condiment" unless they share a term. Phase 4's move to an embedding provider corrects this, but it is not a drop-in swap behind today's interface: the embedder contract and the SQL index both change with it, moving from the sparse term index that suits the low tens of thousands of products to a dedicated vector store at the 200,000 SKUs §3.1 requires.
PCI DSS position
The platform is designed for reduced-scope SAQ A: cardholder data is entered on the payment provider’s hosted page and never traverses or is stored on E-Mall infrastructure. PCI DSS v4.0.1 added an eligibility criterion that the merchant confirm its pages are not susceptible to script attacks. Removing every third-party script and enforcing a nonce-based policy is how this application answers that criterion. No card data exists anywhere in this sandbox: payment is simulated and says so at the point of checkout.
Not yet done
- No independent penetration test or TT-CSIRT review has been carried out. Both are Phase 5 gates in the proposed schedule.
- Rate limiting and account lockout are not implemented in the sandbox.
- Multi-factor authentication for administrator accounts is proposed for delivery, not present here.
- Encryption at rest depends on the hosting tier and is a deployment decision, not an application one.
Vulnerability reports are welcome during evaluation — please route them through the submission contact. See also the privacy notice.