1.0.1
Security release. Fixes the findings from an OWASP audit of the codebase.
1227 tests pass (25 added — every fix has a regression test, because these hid in plain sight). composer audit --locked and npm audit --omit=dev both report zero.
Versioning note. This continues the v1 line started at v1.0.0. The release before that was v13.0.0, whose tag tracked the Laravel major, and Composer still orders
13.0.0above this tag — socomposer create-projectresolves v13.0.0 unless you pin1.0.1explicitly. Thev1tag now points here.
🔴 Critical
Any registered customer could ship goods at the merchant's expense. The dropshipping API group had auth:sanctum and no role check — the only API controller without one. DropshippingService::placeOrder makes a live call to the supplier with the merchant's API key and a caller-supplied payload, and registration is open. Register → mint a token → POST /api/dropshipping/place-order with any items and address → real goods ship, billed to the merchant. No order record, no payment, no limit. track-order was additionally an unscoped IDOR over any supplier reference. Now staff-only on all four endpoints.
🟠 High
- Plaintext passwords written to logs. Failed registration stripped
passwordbut notpassword_confirmation— the same value. The common trigger is a duplicate email, where the password is perfectly valid. TheQueryExceptionpath leaked the bcrypt hash twice, becauseformatMessage()interpolates bindings into the message. - Webhook signing secrets returned on every response. No
$hidden, so listing endpoints returned everywhsec_secret — the keys needed to forge deliveries that consumers validate as authentic. The code claimed "returned once"; it wasn't. - No security headers at all — no CSP, HSTS, X-Frame-Options, nosniff or Referrer-Policy. The admin panels were framable. CSP ships as Report-Only so it can't break Filament/Livewire.
/checkout/processwas public and unthrottled, reaching payment capture with a caller-supplied card token: unlimited card testing.- The installer's key check failed open.
INSTALLER_ENABLED=truewithout a key exposed shell execution,.envrewrite and arbitrary-role user creation to anyone who found the URL. Now fails closed.
🟡 Medium
Guest API rate limiting had collapsed into a single shared bucket — no proxies were trusted, so every client looked like the ingress and one attacker could throttle everyone. Wildcard CORS on api/* is now env-driven. The session cookie now gets Secure outside local/testing. Authentication failures and lockouts are now logged (allowlisting the email out of the credentials array, which holds the password). SSRF targets rejected on webhook URLs.
Known issues, not fixed here
- Public registration is broken, and that bug is the only thing masking an access-control hole.
CreateNewUserassigns astaffrole no seeder creates, so signup rolls back. Behind it, every registrant would join the store's primary team,canAccessPanelreturnstruefor/app, and Article/ProductCollection have no policies (Filament allows by default). These must be fixed together — repairing registration alone opens the store's tenant to every signup. - SVG stored XSS is latent. Product image upload accepts
image/svg+xmlonto a public disk. Currently unreachable (nopublic/storagesymlink) but live the momentstorage:linkruns. Password::default()is min 8 with no complexity or breach check.- The
Dependency Security Auditworkflow is red and has been since before this work — it runscomposer auditwith nocomposer installand no--locked. One flag fixes it. /user/profilerenders only because social login now defaults off; enabling a provider re-breaks it (// use HasConnectedAccounts;is commented out inUser).
Full changelog: v1.0.0...v1.0.1