PDF Remove Security

Remove password & restrictions

Strip owner (“admin”) passwords and the print/copy/edit/assemble restrictions that come with them. If the PDF also has a user password, enter it below — otherwise leave the field blank. Powered by the Foxit PDF SDK (PDFDoc::RemoveSecurity()).

Machine
Foxit PDF SDK version
user password, if any

How it works

The Foxit PDF SDK calls PDFDoc::RemoveSecurity() on the loaded document, which drops the encryption dictionary and clears the permission bitmask. The PDF is then re-saved with e_SaveFlagNoOriginal | e_SaveFlagXRefStream | e_SaveFlagRemoveRedundantObjects so the output is a fresh, fully-unencrypted file with a compressed xref — not just a re-emission of the original.

If a PDF has only an owner (“admin”) password, the SDK can open it without any password supplied and strip the restrictions directly. If it also has a user password, you have to supply that (or the owner password) so the SDK can decrypt the content. Wrong-password attempts return a 401 instead of guessing.

Pick the machine and the SDK version. The identical source (foxit_remove_security.cpp) is compiled four ways — Kramer (Windows) and Jerry (Linux), each on Foxit PDF SDK 11.0 and 11.1 — a controlled 2×2 for separating SDK-release differences from OS/environment differences. Same code, same input; only the OS or the SDK version changes.

Sample implementation code

The full pipeline this demo runs — load with an optional password, inspect the encryption & permission state, strip the security, then compact-save — in each SDK language binding. Condensed for clarity.

#include "common/fs_common.h"
#include "pdf/fs_pdfdoc.h"

using namespace foxit;
using namespace foxit::common;
using namespace foxit::pdf;

int main() {
  Library::Initialize(sn, key);
  PDFDoc doc(L"input.pdf");

  // Empty string is the no-password case. An owner-password-only PDF
  // still loads with "" (GetPasswordType() reports e_PwdNoPassword) and
  // its restrictions get stripped below. A user-password PDF returns
  // e_ErrPassword -- this demo maps that to exit 5 / HTTP 401.
  ErrorCode err = doc.Load(String("password-or-empty"));
  if (err == e_ErrPassword) return 5;      // password required or wrong
  if (err != e_ErrSuccess)  return 3;

  // --- Inspect the security state before removing it ---
  bool   was_encrypted = doc.IsEncrypted();
  int    enc_type      = (int)doc.GetEncryptionType();   // password / cert / rms...
  int    pwd_type      = (int)doc.GetPasswordType();     // none / user / owner
  uint32 perms         = doc.GetUserPermissions();
  // Bit SET = action allowed; bit CLEAR = restricted. e.g.:
  //   0x0004 print   0x0008 modify      0x0010 extract (copy)
  //   0x0100 fill-forms  0x0400 assemble  0x0800 print-high
  bool print_blocked = (perms & 0x0004) == 0;

  // --- Strip the encryption dictionary + permission bitmask ---
  if (!doc.RemoveSecurity()) return 8;

  // Compact re-save: rewrite from in-memory state, compressed xref
  // stream, unreferenced objects pruned -- a fresh unencrypted file,
  // not a re-emission of the original.
  doc.SaveAs(L"unlocked.pdf",
             PDFDoc::e_SaveFlagNoOriginal
           | PDFDoc::e_SaveFlagXRefStream
           | PDFDoc::e_SaveFlagRemoveRedundantObjects);
  Library::Release();
  return 0;
}
using foxit;
using foxit.common;
using foxit.pdf;

Library.Initialize(sn, key);
using var doc = new PDFDoc("input.pdf");

// Empty string is the no-password case. An owner-password-only PDF
// still loads with "" and its restrictions get stripped below. A
// user-password PDF returns e_ErrPassword -> HTTP 401 in this demo.
var err = doc.Load("password-or-empty");
if (err == ErrorCode.e_ErrPassword) return;   // password required or wrong
if (err != ErrorCode.e_ErrSuccess)  return;

// --- Inspect the security state before removing it ---
bool wasEncrypted = doc.IsEncrypted();
var  encType      = doc.GetEncryptionType();   // password / cert / rms...
var  pwdType      = doc.GetPasswordType();     // none / user / owner
uint perms        = doc.GetUserPermissions();
// Bit SET = allowed; bit CLEAR = restricted. e.g.:
//   0x0004 print, 0x0008 modify, 0x0010 extract (copy), 0x0400 assemble
bool printBlocked = (perms & 0x0004) == 0;

// --- Strip the encryption dictionary + permission bitmask ---
if (!doc.RemoveSecurity()) return;

// Compact re-save: fresh unencrypted file, compressed xref,
// unreferenced objects pruned.
doc.SaveAs("unlocked.pdf",
    (int)(PDFDoc.SaveFlags.e_SaveFlagNoOriginal
        | PDFDoc.SaveFlags.e_SaveFlagXRefStream
        | PDFDoc.SaveFlags.e_SaveFlagRemoveRedundantObjects));
Library.Release();
import com.foxit.sdk.common.Library;
import com.foxit.sdk.pdf.PDFDoc;

Library.initialize(sn, key);
PDFDoc doc = new PDFDoc("input.pdf");

// Empty string is the no-password case. An owner-password-only PDF
// still loads with "" and its restrictions get stripped below. A
// user-password PDF returns e_ErrPassword -> HTTP 401 in this demo.
int err = doc.load("password-or-empty".getBytes());
if (err == ErrorCode.e_ErrPassword) return;   // password required or wrong
if (err != ErrorCode.e_ErrSuccess)  return;

// --- Inspect the security state before removing it ---
boolean wasEncrypted = doc.isEncrypted();
int encType = doc.getEncryptionType();        // password / cert / rms...
int pwdType = doc.getPasswordType();          // none / user / owner
long perms  = doc.getUserPermissions();
// Bit SET = allowed; bit CLEAR = restricted. e.g.:
//   0x0004 print, 0x0008 modify, 0x0010 extract (copy), 0x0400 assemble
boolean printBlocked = (perms & 0x0004) == 0;

// --- Strip the encryption dictionary + permission bitmask ---
if (!doc.removeSecurity()) return;

// Compact re-save: fresh unencrypted file, compressed xref,
// unreferenced objects pruned.
doc.saveAs("unlocked.pdf",
    PDFDoc.e_SaveFlagNoOriginal | PDFDoc.e_SaveFlagXRefStream
  | PDFDoc.e_SaveFlagRemoveRedundantObjects);
Library.release();
from FoxitPDFSDKPython3 import *

Library.Initialize(sn, key)
doc = PDFDoc("input.pdf")

# Empty string is the no-password case. An owner-password-only PDF
# still loads with "" and its restrictions get stripped below. A
# user-password PDF returns e_ErrPassword -> HTTP 401 in this demo.
err = doc.Load("password-or-empty")
if err == e_ErrPassword:
    raise SystemExit("password required or wrong")   # -> 401
assert err == e_ErrSuccess

# --- Inspect the security state before removing it ---
was_encrypted = doc.IsEncrypted()
enc_type = doc.GetEncryptionType()      # password / cert / rms...
pwd_type = doc.GetPasswordType()        # none / user / owner
perms = doc.GetUserPermissions()
# Bit SET = allowed; bit CLEAR = restricted. e.g.:
#   0x0004 print, 0x0008 modify, 0x0010 extract (copy), 0x0400 assemble
print_blocked = (perms & 0x0004) == 0

# --- Strip the encryption dictionary + permission bitmask ---
assert doc.RemoveSecurity()

# Compact re-save: fresh unencrypted file, compressed xref,
# unreferenced objects pruned.
doc.SaveAs("unlocked.pdf",
           PDFDoc.e_SaveFlagNoOriginal | PDFDoc.e_SaveFlagXRefStream
         | PDFDoc.e_SaveFlagRemoveRedundantObjects)
Library.Release()
// Foxit PDF SDK for Node.js (naming follows the Node binding conventions)
const { Library, PDFDoc, ErrorCode } = require('@foxitsoftware/foxit-pdf-sdk-node');

Library.initialize(sn, key);
const doc = new PDFDoc('input.pdf');

// Empty string is the no-password case. An owner-password-only PDF
// still loads with '' and its restrictions get stripped below. A
// user-password PDF returns e_ErrPassword -> HTTP 401 in this demo.
const err = doc.load('password-or-empty');
if (err === ErrorCode.e_ErrPassword) throw new Error('password required'); // -> 401
if (err !== ErrorCode.e_ErrSuccess)  throw new Error('load failed: ' + err);

// --- Inspect the security state before removing it ---
const wasEncrypted = doc.isEncrypted();
const encType = doc.getEncryptionType();      // password / cert / rms...
const pwdType = doc.getPasswordType();        // none / user / owner
const perms   = doc.getUserPermissions();
// Bit SET = allowed; bit CLEAR = restricted. e.g.:
//   0x0004 print, 0x0008 modify, 0x0010 extract (copy), 0x0400 assemble
const printBlocked = (perms & 0x0004) === 0;

// --- Strip the encryption dictionary + permission bitmask ---
if (!doc.removeSecurity()) throw new Error('RemoveSecurity failed');

// Compact re-save: fresh unencrypted file, compressed xref,
// unreferenced objects pruned.
doc.saveAs('unlocked.pdf',
    PDFDoc.e_SaveFlagNoOriginal
  | PDFDoc.e_SaveFlagXRefStream
  | PDFDoc.e_SaveFlagRemoveRedundantObjects);
Library.release();

Samples are condensed for clarity — production code should check every return value and wrap SDK calls in the binding’s exception handling. Exact class/module names can differ slightly between SDK releases; the C++ tab matches the real source this demo runs (kept alongside each binary as foxit_remove_security.cpp in server_11_0/ and server_11_1/).