
Research
Shai-Hulud Descends to Hades: Miasma Worm Campaign Spreads with New PyPI Wave
Socket found 37 malicious PyPI wheels that abuse Python startup hooks to launch a Bun-powered credential stealer tied to Mini Shai-Hulud/Miasma.
@pdfsmaller/pdf-decrypt
Advanced tools
Full-featured PDF decryption with AES-256 and RC4 support. Companion to @pdfsmaller/pdf-encrypt. Powers PDFSmaller.com's PDF unlock tool.
Full-featured PDF decryption with AES-256 and RC4 support. Built for browsers, Node.js 18+, Cloudflare Workers, and Deno.
Companion to @pdfsmaller/pdf-encrypt. Powers PDFSmaller.com's Unlock PDF tool.
pdf-lib as a peer dependencynpm install @pdfsmaller/pdf-decrypt pdf-lib
import { decryptPDF } from '@pdfsmaller/pdf-decrypt';
import fs from 'fs';
const pdfBytes = fs.readFileSync('encrypted.pdf');
const decrypted = await decryptPDF(new Uint8Array(pdfBytes), 'my-password');
fs.writeFileSync('decrypted.pdf', decrypted);
decryptPDF(pdfBytes, password)Decrypt a password-protected PDF. Supports both AES-256 and RC4 encryption — the algorithm is detected automatically.
| Parameter | Type | Description |
|---|---|---|
pdfBytes | Uint8Array | The encrypted PDF file as bytes |
password | string | The user or owner password |
Returns: Promise<Uint8Array> — The decrypted PDF bytes
Throws:
"This PDF is not encrypted" — if the PDF has no encryption dictionary"Incorrect password" — if neither user nor owner password matches"Unsupported encryption" — if the encryption version is not supportedisEncrypted(pdfBytes)Check if a PDF is encrypted without attempting to decrypt it.
| Parameter | Type | Description |
|---|---|---|
pdfBytes | Uint8Array | The PDF file as bytes |
Returns: Promise<{ encrypted: boolean, algorithm?: 'AES-256' | 'RC4', version?: number, revision?: number, keyLength?: number }>
import { decryptPDF, isEncrypted } from '@pdfsmaller/pdf-decrypt';
// Check encryption type first
const info = await isEncrypted(pdfBytes);
if (info.encrypted) {
console.log(`Encrypted with ${info.algorithm}`);
const decrypted = await decryptPDF(pdfBytes, password);
}
import { encryptPDF } from '@pdfsmaller/pdf-encrypt';
import { decryptPDF } from '@pdfsmaller/pdf-decrypt';
// Encrypt
const encrypted = await encryptPDF(pdfBytes, 'secret');
// Decrypt
const decrypted = await decryptPDF(encrypted, 'secret');
<input type="file" id="pdf-input" accept=".pdf" />
<input type="password" id="password" placeholder="Enter password" />
<button id="decrypt-btn">Decrypt</button>
<script type="module">
import { decryptPDF } from '@pdfsmaller/pdf-decrypt';
document.getElementById('decrypt-btn').addEventListener('click', async () => {
const file = document.getElementById('pdf-input').files[0];
const password = document.getElementById('password').value;
const pdfBytes = new Uint8Array(await file.arrayBuffer());
try {
const decrypted = await decryptPDF(pdfBytes, password);
// Download
const blob = new Blob([decrypted], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'decrypted.pdf';
a.click();
} catch (e) {
alert(e.message);
}
});
</script>
| Algorithm | PDF Version | Key Length | Status |
|---|---|---|---|
| AES-256 (V=5, R=6) | 2.0 (ISO 32000-2) | 256-bit | Supported |
| RC4 (V=2, R=3) | 1.4+ (ISO 32000-1) | 128-bit | Supported |
| RC4 (V=1, R=2) | 1.1+ | 40-bit | Supported |
| AES-128 (V=4, R=4) | 1.6+ | 128-bit | Not yet supported |
| Feature | pdf-decrypt | pdf-decrypt-lite |
|---|---|---|
| AES-256 | Yes | No |
| RC4 128-bit | Yes | Yes |
| RC4 40-bit | Yes | Yes |
| Batched async | Yes | No (sync only) |
| Size | ~18KB | ~8KB |
| Use case | Full decryption | RC4-only, minimal |
Choose pdf-decrypt-lite if you only need RC4 and want the smallest possible bundle. Choose pdf-decrypt for full AES-256 + RC4 support.
MIT — PDFSmaller.com
FAQs
Full-featured PDF decryption with AES-256 and RC4 support. Companion to @pdfsmaller/pdf-encrypt. Powers PDFSmaller.com's PDF unlock tool.
We found that @pdfsmaller/pdf-decrypt demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
Socket found 37 malicious PyPI wheels that abuse Python startup hooks to launch a Bun-powered credential stealer tied to Mini Shai-Hulud/Miasma.

Security News
RubyGems and Bundler 4.0.13 introduced an opt-in cooldown feature that delays newly published gems during dependency resolution.

Security News
pnpm 11.5 now recognizes npm staged publish approvals in release metadata, preventing those releases from being mistaken for lower-trust package publishes.