Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Blasp Laravel Package

blaspsoft/blasp

Blasp is an advanced profanity filter for Laravel with a driver-based architecture, multi-language support, severity scoring, masking strategies, Eloquent integration, middleware, validation rules, and testing utilities. Clean fluent API for detecting and filtering profanity.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

Blasp is a leaf dependency with an intentionally small blast radius: no database migrations, no queue workers, no external network calls, no service container overrides beyond its own bindings. It auto-registers a service provider, a Blasp facade, a blasp middleware alias, a @clean Blade directive, and Str/Stringable macros. That is the correct shape for a policy utility — it can be adopted, pinned, and removed without architectural debt.

The important architectural property is that detection is local and deterministic. No content leaves the application boundary, which is a material advantage over hosted moderation APIs (Perspective, AWS Comprehend, OpenAI Moderation) for any product with PII, GDPR, HIPAA-adjacent, or data-residency obligations. That is the strongest strategic argument for this package over the alternatives.

Enforcement surfaces are layered and independently selectable — validation rule, middleware, Eloquent trait, view directive, programmatic facade. That allows a phased rollout where read paths and write paths are hardened on different schedules. The DriverInterface + PendingCheck fluent builder suggests the abstraction is not leaky enough to trap us, but swapping to a hosted provider later would mean abandoning the trait/middleware/rule ergonomics, not just the engine.

Integration feasibility

Low. composer require, publish blasp-config, done. PHP 8.2+ is the only meaningful gate. The API is idiomatic Laravel: fluent builders, enum-based severity, JsonSerializable/Countable/Stringable result objects, a Blasp::fake() test double with assertions. A mid-level Laravel developer can be productive in half a day.

The real integration work is not code — it is policy definition: which fields are checked, which severity threshold applies per surface, sanitize vs. reject, and who owns the wordlist. That is product/legal work disguised as a config file.

Technical risk

Risk Severity Notes
False positives (Scunthorpe problem) High Regex + separator + substitution matching on real names, place names, medical/legal terms, and non-English text. A curated false_positives list exists but is necessarily incomplete and locale-blind.
False negatives / evasion High Leet-speak mappings and 3-character separator tolerance are enumerable and will be defeated by novel obfuscation, homoglyphs, zero-width joiners, RTL override characters, and non-Latin scripts. README makes no claim about Unicode normalization or ZWJ stripping.
Multilingual claims vs. reality Medium-High EN/ES/DE/FR dictionaries exist, but the phonetic driver explicitly documents supported_languages => ['english'] and is metaphone()-based. Marketing ("multi-language") and capability (English-centric phonetic) diverge.
Global-state toggles under Octane Medium-High withoutBlaspChecking() and the middleware's request mutation imply static/global state. In a long-running worker (Octane, Swoole), a leaked toggle or mutated request is a cross-request contamination vector. Must be verified before any Octane deployment.
Regex performance / ReDoS Medium README asserts complexity is "low enough for PHP-FPM environments" — that is a design claim, not a benchmark. No published p99 latency data at realistic payload sizes, and no adversarial-input analysis.
Cache correctness Medium cache.results keys on content hash with 24h TTL. Dictionary/config changes leave stale verdicts for up to a day with no described invalidation hook. Content-hash keying also means near-zero hit rate on genuinely novel user text while still writing unbounded keys into the cache store.
Eloquent trait mutates on save Medium Silent field rewriting breaks auditability, interacts awkwardly with isDirty, observers, updateQuietly, and is bypassed entirely by Model::insert() / query-builder writes. Sanitize-by-default is a surprising default.
Middleware defaults Medium fields => ['*'] checks every request field; action => 'reject' returns 422. Applied globally, this silently changes API contracts and inspects fields (nested arrays, JSON bodies, file metadata) nobody intended.
Opaque severity score Medium A 0–100 score with an undocumented formula, exposed as a validation rule (Profanity::maxScore(50)), couples business policy to an internal implementation detail that can shift between minor versions.
Adoption / bus factor Medium 356 stars, 0 dependents, single-org maintainer, modest composite score. v4 was a ground-up rewrite — evidence that major versions break. No signals of enterprise production usage at scale.
Version metadata anomaly Low PHP 8.2+ alongside Laravel 8.0+ is internally inconsistent (Laravel 8 predates PHP 8.2 support), and the listed last-release date is future-dated. Verify the actual CI matrix and Packagist history before trusting the compatibility claim.

Key questions

  1. What are the measured false-positive and false-negative rates against our corpus — support tickets, usernames, product names, non-English content, user-generated tags — not the vendor's examples?
  2. What is p95/p99 latency for check() on 1KB, 10KB, and 100KB payloads, and has anyone fuzzed the regex driver with adversarial separator/homoglyph input?
  3. Does the driver normalize Unicode (NFKC), strip zero-width and bidi control characters, and handle RTL and non-Latin scripts at all — or is detection silently ASCII-scoped?
  4. Is there a documented cache invalidation path when dictionaries or severity config change? Can we scope the cache to a named store and cap it?
  5. Is withoutBlaspChecking() request-scoped or process-global? Has the package been validated under Laravel Octane?
  6. Is the severity score formula versioned and covered by a stability guarantee, or can it drift between minor releases?
  7. Who owns wordlist curation and false-positive triage internally, and what is the SLA for a user-facing over-mask complaint?
  8. What is the maintainer's responsiveness on issues, and is there a security disclosure process (the project has CI but the README does not document one)?

Integration Approach

Stack fit

Good fit for a conventional Laravel monolith or API on PHP 8.2+. It is driver-based and config-first, which matches how we already structure environment-specific behavior. No infrastructure dependencies beyond the cache store we already run. It should be treated as a policy library, not a security control — pair it with rate limiting, reporting flows, and human review for high-severity cases; do not present it to legal/compliance as a complete content-safety solution.

Migration path

There is no incumbent to migrate from in most cases, so the path is additive and reversible. Recommended staged adoption:

  1. composer require blaspsoft/blasp with an exact-version constraint; publish config only (not languages) initially.
  2. Pin default => 'regex' explicitly rather than relying on env defaults, so behavior cannot shift on deploy.
  3. Enable events => true and ProfanityDetected listeners with no enforcement — pure observation for 2–4 weeks to build an internal FP/FN baseline on real traffic.
  4. Add Profanity validation rules on the lowest-risk, highest-value field (e.g., display name).
  5. Promote to sanitize mode on public-facing comment/bio fields.
  6. Enable reject mode and blasp middleware only on surfaces where a 422 is an acceptable UX, and never with fields => ['*'] — enumerate fields explicitly.
  7. Apply the Blaspable trait model-by-model, defaulting to sanitize, and only after confirming no ETL, import, or admin tooling depends on byte-exact attribute values.

Compatibility

Verify against the Laravel versions we actually run. The 8.0+ claim should be treated as aspirational until the CI matrix confirms it; realistically target the current LTS plus one prior. PHP 8.2+ is a hard floor — confirm our runtime images and any shared libraries meet it before committing. Check that our cache store supports the driver and TTL semantics used. If we run Octane, gate adoption on resolving the global-state question first.

Sequencing

Sequence around risk tolerance, not code complexity. The code is a one-day task; the policy is a multi-sprint conversation with Trust & Safety, Legal, and Support. Two ordering constraints matter: (a) observational mode must precede enforcement, or we ship blind; and (b) sanitization on read paths (Blade @clean) should land before rejection on write paths, because masking is recoverable and rejection is not.

Operational Impact

Maintenance

Low code maintenance, non-trivial content maintenance. The package itself is a pinned Composer dependency with a changelog and tagged releases; expect to review it at each major Laravel upgrade and on any v5. The ongoing cost is wordlist and false-positive curation — this is an unglamorous, permanent operational commitment that must be assigned to a named owner. Budget for a monthly review of over-mask complaints and a curated allow list per locale.

Treat major versions as breaking: v4 was a ground-up rewrite, so pinning and reading upgrade guides is mandatory. The score() formula and severity categorization are the most likely silent-change surfaces.

Support

No vendor SLA. Support is community + internal. Establish: an internal owner for the package, a documented escalation path for "the filter blocked a legitimate user," and a policy for emergency allow-listing. Because enforcement failures are user-visible and often public (a blocked comment, a mangled name), support load will be driven by false positives, not by bugs.

Scaling

Cost is CPU on the request path, proportional to payload size × driver count. Mitigations, in order of preference:

  • Use the pattern driver for high-volume, low-obfuscation-risk fields; reserve regex/phonetic/pipeline for high-risk, low-volume surfaces.
  • Never run pipeline across all fields — union-merge semantics mean every driver runs on every check.
  • Restrict the results cache to low-cardinality content (templates, static copy) or use a short TTL; unique user text defeats content-hash caching while still inflating the cache store.
  • Offload bulk/backfill scanning (imports, historical re-scans) to queued jobs, not request handlers.
  • Use checkMany() for batch paths to amortize per-call overhead.

Set a hard input length cap before check() is invoked — that single control mitigates both cost and adversarial-input risk.

Failure modes

Failure Blast radius Detection Mitigation
Over-masking legitimate content User trust, public embarrassment User reports; event log Observation phase, curated allow-list, sanitize-before-reject sequencing
Under-masking (evasion) Safety/compliance exposure Sampled human review; report queue Layer with reporting + human moderation; do not rely on the filter alone
ProfanityRejectedException uncaught in a save 500s, partial writes Error rate spike on write endpoints Global exception handler mapping to 422; wrap transactional writes
Middleware 422 on unexpected fields Broken API clients 4xx spike post-deploy Explicit field lists, never ['*'] in production
Stale verdicts after dictionary update Inconsistent enforcement Verdict divergence across nodes Purge results cache on config deploy; version the cache key
Cache store outage or eviction storm Latency spike on writes p99 regression Fail-open to uncached check; alert on cache error rate
Regex backtracking on crafted input Worker pool exhaustion p99 latency, 504s Input length caps, driver downgrade on public endpoints, load test with adversarial strings
State leak under Octane Cross-request contamination Non-deterministic verdicts Validate before Octane adoption; prefer explicit per-call options over global toggles
Model writes bypassing the trait Policy gaps in ETL/admin paths Periodic audit of write paths Enforce at validation/middleware layer too; audit insert()/query-builder usage

Ramp-up

Very low for engineering — one developer, one day, plus a day for test-double integration and listener wiring. Blasp::fake() materially reduces the cost of writing deterministic tests around enforcement, which is a real quality-of-life win.

The genuine ramp-up cost sits outside engineering: defining severity policy per surface, negotiating acceptable false-positive behavior with Support, and standing up an allow-list governance process. Plan for a two-to-four-week observational runway before any enforcement ships, and treat the wordlist as a living product artifact rather than a config constant.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style