artisanpack-ui/security
Core Laravel security toolkit for ArtisanPack UI: input sanitization, output escaping, KSES filtering, validation rules, security headers, XSS protection, rate limiting, and CSP with nonces, presets, and violation reporting, plus audit, scan, and benchmark Artisan commands.
Architecture fit. The package is a conventional Laravel package: a service provider, two facades (Security, Csp), global helper functions, a publishable config file, route middleware aliases, Blade directives/components, and Artisan commands. There is nothing exotic in the integration surface — it slots into the framework the same way laravel/sanctum or spatie/laravel-csp would. That is the strongest part of the evaluation: a Laravel team can reason about it without new mental models.
The capability set divides cleanly into three tiers of value:
sanitizeEmail, sanitizeInt, escHtml, NoHtml/SecureUrl validation rules. Laravel already gives you Blade auto-escaping and typed validation rules; adopting this package for these alone is not justified.security.headers middleware, rate limiter presets. Small, well-understood, and there are battle-tested alternatives.csp:stats/csp:prune commands) and the audit/scan command suite (security:audit, security:scan-deps, security:check-config, SARIF/JUnit report generators for CI).The 2.0 repackaging into a core package plus six siblings (security-auth, rbac, secure-uploads, compliance, etc.) is architecturally sound — it avoids a monolith — but it means this package is explicitly not a complete security story. Any roadmap that assumes "install security and we're covered" is wrong; you are committing to a package family.
Integration feasibility. High mechanically, low in confidence. composer require plus one publish step. PHP 8.2+ / Laravel 10–13 with a clean constraint widening in 2.0.2.
Technical risk. This is where the assessment gets uncomfortable, because the risk profile is inverted relative to the stakes:
export-ignore rule that stripped CspTest from the release tarball, causing Target class ... does not exist at package discovery for every consumer. That is a release-pipeline bug in a security-critical dependency, and it shipped as a patch. Separately, sanitizeFloat() was declared float but returned a string, raising TypeError on every call under strict_types=1 — a bug that existed until 2.1.0, implying that code path had no meaningful test coverage until recently.ap.security.sanitizedInput and ap.security.escapedOutput receive the already-sanitized value and may return anything, including the original. The README is admirably candid about this, but as a TPM I read it as: the package's guarantees are only as strong as the weakest filter a future developer registers. This needs a written internal policy, not just a code review.Key questions for the maintainer / our own review.
SECURITY.md, a private disclosure channel, and a stated patch SLA? None is visible in the supplied docs.sanitizeFloat escape?artisanpack-ui/hooks a hard dependency, and can the hook layer be disabled entirely if we don't want the override surface?Stack fit. Direct fit for a Laravel 10–13 application on PHP 8.3+. The sibling-package structure means we adopt only what we need; artisanpack-ui/security alone is a reasonable starting scope. Note that this is a Blade/SSR-oriented package — the CSP nonce helper and <x-csp-nonce> component assume server-rendered templates. If the front end is a decoupled SPA, the CSP half delivers much less value and the cost/benefit shifts toward "headers middleware + audit commands only."
Compatibility and conflict. Do not run this alongside spatie/laravel-csp or bepsvpt/secure-headers. Overlapping CSP emitters and duplicate Content-Security-Policy headers produce a browser-enforced intersection of policies that is miserable to debug. Pick one emitter per concern and document it in the ADR.
Migration path. Greenfield: low risk, but pin exactly (2.1.*) and read the 1.x → 2.x UPGRADE.md anyway so you understand what moved where. Brownfield: this is not a lift-and-shift. Treat it as six independent adoptions, not one. Any existing app carrying 1.x expectations — auth, RBAC, 2FA — will find those capabilities gone, not deprecated. If a team is mid-flight on a 1.x integration, freeze that and finish before touching 2.x.
Sequencing. Roughly a four-to-six week ramp for one engineer at part-time allocation:
security:baseline and security:check-config to see what it thinks of our current posture. No traffic.security.headers on a staging route group. Verify nothing breaks behind our CDN/proxy — header rewriting at the edge is the classic failure here.report-only, stand up the violation endpoint, schedule csp:prune. Let real traffic accumulate. Use csp:stats to triage. This is the phase that consumes the calendar; do not compress it.escHtml through Blade — that duplicates framework behavior and creates double-escaping bugs.Explicitly out of scope for v1: hooks, the Livewire CSP dashboard, and any sibling package beyond what an existing requirement already forces.
Maintenance. You are taking a dependency on a package with a single-digit star count and no visible commercial backing. Bus factor is the headline risk. Mitigations: pin to ~2.1.0, route updates through Renovate with a manual-approval rule for this package specifically, and maintain a short internal fork-or-vendor contingency note. Realistically the escape hatch is easy — the valuable surfaces (headers middleware, CSP policy builder, nonce helper) are a few hundred lines and independently reimplementable if the project stalls.
Support. Documentation is genuinely above average for a package this size: README, docs/, UPGRADE.md, per-version changelogs, and a documented hook contract with payload signatures. That partly offsets the low adoption. There is no support contract, no issue-triage guarantee, and no disclosure policy — which for a security dependency should be raised in the adoption decision, not waved through. Budget internal ownership: name a maintainer-of-record on our side.
Scaling. Two things scale non-linearly. First, CSP violation storage: every blocked asset from every client writes a row. With csp.reporting.storeViolations on, a misconfigured directive or a browser extension storm can flood the table — csp:prune must be scheduled before enforcement is turned on, with retention configured and an alert on table growth. Second, rate limiting: the named limiters (web, api, login, password_reset) depend on the cache driver. On a single node with the file driver that is fine; on a multi-node deployment without a shared Redis/Memcached backend, limits are per-node and effectively multiplied by fleet size. Verify the cache store before enabling api.rate_limit and login limiters.
Nonce generation itself is cheap; per-request overhead is negligible.
Failure modes to plan for.
class does not exist incident shows this package can take down the whole app at package discovery. Any deploy that bumps this dependency needs a full boot smoke test, not just unit tests.Strict preset applied to a Livewire app instead of the Livewire preset) blocks scripts and renders pages functionally dead while returning HTTP 200. Monitoring must catch console/CSP error rates, not just status codes — which is exactly why report-only precedes enforce.kses() allowed-tag lists strip markup from user content on save. This is a data-loss failure mode that surfaces days later in support tickets. Run against a production data sample in staging before enabling.ap.security.escapedOutput returning the original value. Treat hook registration as a privileged change requiring security review.csp:stats window that includes bot traffic or a pre-deploy snapshot.Ramp-up. API learning curve is low — the helper and middleware surface is self-explanatory in an afternoon. The conceptual cost sits in CSP: directive semantics, nonce propagation through the asset pipeline, and the report-only-to-enforce discipline. Allocate the time to whoever owns the front-end build, not just the backend engineer, or step 3 above will stall.
Recommendation. Conditional pilot. Adopt the CSP and audit-command tier — that is where the package earns its place — in a non-production environment with report-only enforcement, pinned version, and a named internal owner. Do not adopt it as a general sanitization/escaping layer, where Laravel's native facilities are better validated and carry no third-party risk. Reassess after one quarter of usage and one upstream release cycle: if the release-hygiene issues recur or the project shows no adoption growth, fall back to a thin in-house implementation of the headers and CSP surfaces, which is a bounded, well-understood piece of work.
How can I help you explore Laravel packages today?