laminblur / filament-pdf-sanitizer
A Filament plugin that automatically sanitizes PDF files by removing JavaScript, forms, and annotations before upload to prevent WAF blocking
Package info
github.com/laminblur/filament-pdf-sanitizer
Language:JavaScript
pkg:composer/laminblur/filament-pdf-sanitizer
Requires
- php: ^8.2
- filament/filament: ^3.0
- illuminate/support: ^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0
README
A Filament plugin that automatically sanitizes PDF files by removing JavaScript, forms, annotations, and embedded scripts before upload. This prevents AWS WAF and other security systems from blocking PDF uploads that contain executable content.
๐ฏ Problem Solved
When uploading PDFs through Filament's FileUpload component, files containing embedded JavaScript or interactive elements can be blocked by security systems like AWS WAF (Web Application Firewall). This plugin automatically sanitizes PDFs client-side before upload, ensuring they pass security checks while preserving all visual content.
โจ Features
- ๐ Automatic PDF Sanitization - Removes JavaScript, forms, and annotations from PDFs before upload
- ๐ Zero Configuration - Works out of the box with Filament FileUpload components
- โก Lazy Loading - Only loads PDF libraries when file inputs are detected (reduces initial bundle size)
- ๐ฏ Transparent - Works seamlessly with Livewire file uploads without user intervention
- ๐ฆ Lightweight - Optimized bundle size with code splitting and dynamic imports
- ๐ Smart Caching - Caches sanitized files to prevent re-processing on retry
- ๐ก๏ธ WAF Compatible - Prevents AWS WAF and other security systems from blocking uploads
- ๐ Progress Indicators - Visual feedback during PDF sanitization
- โ๏ธ Configurable - Customize quality, scale, file size limits, and more
- ๐งน Memory Efficient - Automatic cleanup of canvas elements and memory management
- ๐จ Error Handling - Graceful error handling with console logging
- ๐ File Size Limits - Configurable maximum file size and page count limits
๐ Requirements
- PHP 8.2 or higher
- Laravel 11 or 12
- Filament 3.x
- Node.js dependencies:
jspdfandpdfjs-dist(see PDF.js version compatibility below)
๐ฆ Installation
Step 1: Install via Composer
Install the package directly from Packagist:
composer require laminblur/filament-pdf-sanitizer
Step 2: Install NPM Dependencies
npm install jspdf pdfjs-dist
PDF.js version: The package ships a PDF.js worker that matches a specific pdfjs-dist version. To avoid "API version does not match the Worker version" errors, pin pdfjs-dist in your app's package.json to the same version as the bundled worker (e.g. "pdfjs-dist": "5.4.449"). If you want to use a different or newer pdfjs-dist, set workerPath to the worker from your installed version (see Configuration and Troubleshooting).
Step 3: Publish Assets
php artisan vendor:publish --tag=filament-pdf-sanitizer-assets php artisan vendor:publish --tag=filament-pdf-sanitizer-config
Note: The PDF worker file is automatically copied to
public/vendor/filament-pdf-sanitizer/when the package is installed. If you need to update it, run the publish command again with the--forceflag. The default worker matches a specificpdfjs-distversion; your app'spdfjs-distversion must match, or setworkerPathto your own worker.
Step 4: Update Vite Config (Optional)
If you want to explicitly include the package assets in your build, add to vite.config.js:
import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; export default defineConfig({ plugins: [ laravel({ input: [ 'resources/css/app.css', 'resources/js/app.js', 'resources/css/filament/admin/theme.css', 'resources/js/vendor/filament-pdf-sanitizer/init.js', // Add this ], refresh: true, }), ], optimizeDeps: { include: ['pdfjs-dist', 'jspdf'], }, build: { rollupOptions: { output: { manualChunks: undefined, }, }, }, });
Step 5: Rebuild Assets
npm run build
๐ Usage
Basic Usage
Add the plugin to your Filament panel provider:
<?php namespace App\Providers\Filament; use Filament\Panel; use Filament\PanelProvider; use Laminblur\FilamentPdfSanitizer\FilamentPdfSanitizerPlugin; class AdminPanelProvider extends PanelProvider { public function panel(Panel $panel): Panel { return $panel ->plugins([ FilamentPdfSanitizerPlugin::make(), // ... other plugins ]); } }
That's it! The plugin will automatically sanitize all PDF uploads in your Filament panels.
Configuration Options
You can configure the plugin in two ways:
Method 1: Plugin Methods (Per Panel)
FilamentPdfSanitizerPlugin::make() ->workerPath('/custom/path/to/pdf.worker.min.js') // Use your pdfjs-dist version's worker to avoid version mismatch ->scale(2.0) // Higher quality (default: 1.5) ->quality(0.95) // JPEG quality 0.0-1.0 (default: 0.85) ->maxFileSizeMb(100) // Max file size in MB (default: 50) ->maxPages(100) // Max pages to process (default: null = unlimited) ->showProgress(true) // Show progress indicator (default: true) ->logErrors(true) // Log errors to console (default: true)
Method 2: Config File (Global)
Publish and edit the config file:
php artisan vendor:publish --tag=filament-pdf-sanitizer-config
Edit config/pdf-sanitizer.php:
return [ /* |-------------------------------------------------------------------------- | PDF Worker Path |-------------------------------------------------------------------------- | | The path to the PDF.js worker file. This file is required for PDF | parsing and rendering. The default worker matches pdfjs-dist 5.4.449. | If your app uses a different pdfjs-dist version, set this to the worker | from your installed pdfjs-dist (e.g. copy from node_modules to public). | */ 'worker_path' => '/vendor/filament-pdf-sanitizer/pdf.worker.min.js', /* |-------------------------------------------------------------------------- | Enable PDF Sanitization |-------------------------------------------------------------------------- | | Set to false to disable PDF sanitization globally. | */ 'enabled' => true, /* |-------------------------------------------------------------------------- | PDF Rendering Scale |-------------------------------------------------------------------------- | | The scale factor for rendering PDF pages. Higher values produce better | quality but larger file sizes. Recommended range: 1.0 - 3.0 | */ 'scale' => 1.5, /* |-------------------------------------------------------------------------- | JPEG Quality |-------------------------------------------------------------------------- | | The JPEG quality for rendered pages (0.0 - 1.0). Higher values produce | better quality but larger file sizes. Recommended range: 0.7 - 0.95 | */ 'quality' => 0.85, /* |-------------------------------------------------------------------------- | Maximum File Size (MB) |-------------------------------------------------------------------------- | | Maximum PDF file size to sanitize. Files larger than this will be | skipped. Set to null to disable size checking. | */ 'max_file_size_mb' => 50, /* |-------------------------------------------------------------------------- | Maximum Pages |-------------------------------------------------------------------------- | | Maximum number of pages to process. PDFs with more pages will be | skipped. Set to null to disable page limit. | */ 'max_pages' => null, /* |-------------------------------------------------------------------------- | Show Progress Indicator |-------------------------------------------------------------------------- | | Whether to show a visual progress indicator during sanitization. | */ 'show_progress' => true, /* |-------------------------------------------------------------------------- | Log Errors |-------------------------------------------------------------------------- | | Whether to log sanitization errors to the browser console. | */ 'log_errors' => true, ];
๐ง How It Works
- Detection: The plugin detects when a PDF file is selected in a file input
- Validation: Checks file size and page count limits (if configured)
- Sanitization: Each PDF page is rendered to a canvas, converted to a JPEG image, and rebuilt as a clean PDF
- Progress: Shows visual progress indicator during sanitization (if enabled)
- Interception: The sanitized PDF replaces the original file before the upload request is sent
- Caching: Sanitized files are cached using WeakMap to prevent re-processing on retry
- Cleanup: Canvas elements and memory are automatically cleaned up after processing
What Gets Removed โ
- JavaScript actions and event handlers
- PDF forms and interactive elements
- Annotations and comments
- Embedded objects and widgets
- Metadata scripts
- JavaScript-based links
What Gets Preserved โ
- Visual content (text, images, graphics)
- Page layout and formatting
- Vector graphics and drawings
- File structure and organization
PDF.js version compatibility
The plugin uses PDF.js (via pdfjs-dist) for parsing and the library runs a worker in a separate file. The main bundle and the worker must be the same version or you get a runtime error. The default worker shipped with this package matches a specific pdfjs-dist version (e.g. 5.4.449). Either pin your app's pdfjs-dist to that version, or set workerPath to the worker from your installed pdfjs-dist. See Installation and Troubleshooting.
๐ Browser Support
- โ Chrome/Edge (latest)
- โ Firefox (latest)
- โ Safari (latest)
๐ Troubleshooting
API version does not match the Worker version
If you see: The API version "X.X.XXX" does not match the Worker version "X.X.XXX":
The PDF.js main library (from your app's bundled pdfjs-dist) and the worker file must be the same version. The package's default worker is tied to a specific build (e.g. 5.4.449).
Fix 1 โ Pin pdfjs-dist to match the default worker:
In your app's package.json, use the exact version (no ^):
"pdfjs-dist": "5.4.449"
Then npm install and rebuild. You can also force this with npm overrides or yarn/pnpm resolutions if another dependency pulls a different version.
Fix 2 โ Use your app's worker:
If you want a different or newer pdfjs-dist:
-
Install the version you need:
npm install pdfjs-dist@x.x.xxx -
Copy the worker from
node_modules/pdfjs-dist/build/pdf.worker.min.mjs(or.min.js) to yourpublic/directory (e.g. at build time or manually). -
Set the worker path to that file:
FilamentPdfSanitizerPlugin::make()->workerPath('/path/to/your/pdf.worker.min.js')
or in
config/pdf-sanitizer.php:'worker_path' => '/path/to/your/pdf.worker.min.js'
PDF Worker Not Found
If you see errors about the PDF worker file (or a version mismatch, see above):
-
The worker file should be automatically copied when the package is installed. If it's missing, publish assets:
php artisan vendor:publish --tag=filament-pdf-sanitizer-assets --force
-
Verify the file exists at:
public/vendor/filament-pdf-sanitizer/pdf.worker.min.js -
Verify the file is accessible via URL:
/vendor/filament-pdf-sanitizer/pdf.worker.min.js -
If the file still doesn't exist, ensure the
publicdirectory is writable and try clearing the application cache:php artisan cache:clear php artisan config:clear
Upload Still Blocked
If uploads are still being blocked:
- โ Check that the plugin is registered in your panel provider
- โ Verify the PDF worker file is accessible at the configured path
- โ Check browser console for JavaScript errors
- โ
Ensure npm dependencies are installed:
npm install jspdf pdfjs-dist - โ
Rebuild assets:
npm run build
Build Errors
If you encounter Vite build errors:
- Ensure JavaScript files are published to
resources/js/vendor/filament-pdf-sanitizer/ - Check your
vite.config.jsincludes the package assets (optional) - Run
npm run buildto rebuild assets - Clear Vite cache:
rm -rf node_modules/.vite(Linux/Mac) orRemove-Item -Recurse -Force node_modules\.vite(Windows)
File Upload Not Working
If file uploads stop working:
- Check browser console for errors
- Verify Livewire is properly initialized
- Ensure the plugin is only registered once (check for duplicate plugin registrations)
- Try clearing browser cache and rebuilding assets
๐ Performance
- Initial Bundle Impact: ~0KB (lazy loaded)
- When Active: ~800KB (pdfjs-dist + jspdf, loaded only when PDF is detected)
- Sanitization Time: ~1-3 seconds per PDF (depends on page count and complexity)
๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
๐ License
This project is open-sourced software licensed under the MIT license.
๐ Acknowledgments
- Built for Filament PHP
- Uses PDF.js for PDF parsing
- Uses jsPDF for PDF generation
๐ Support
For issues and questions, please open an issue on GitHub.
๐ Links
Made with โค๏ธ for the Filament community