IRONSOFTWAREHOME
MIGRATION GUIDES

How to Migrate from wkhtmltopdf to IronPDF in C#

Curtis Chau
Curtis Chau
Updated: August 1, 2026

wkhtmltopdf has been a widely-used tool for converting HTML documents to PDF using Qt 4.8 + QtWebKit. Despite its popularity among developers for its command-line capabilities and free licensing, the project now presents critical security risks that can no longer be ignored. The GitHub repository was archived on January 2, 2023; the last upstream release is 0.12.6 from June 11, 2020; and CVE-2022-35583 (CVSS 9.8, SSRF) remains unpatched.

This guide provides a complete migration path from wkhtmltopdf to IronPDF, with step-by-step instructions, code comparisons, and practical examples for professional .NET developers who need to eliminate this security risk from their applications.

Critical Security Warning: CVE-2022-35583

wkhtmltopdf contains a critical security vulnerability that will never be fixed:

IssueDetailStatus
CVE-2022-35583 (SSRF, CWE-918)CRITICAL (CVSS 9.8)UNPATCHED - disputed by maintainers
GitHub repo archivedRead-onlyJan 2, 2023
Last upstream release0.12.6June 11, 2020
Underlying engineQt 4.8 + QtWebKit (Qt 4.8 EOL 2015)OBSOLETE
CSS Grid SupportNoneBroken
Flexbox SupportPartialBroken
ES6+ JavaScriptLimitedBroken

How the SSRF Attack Works

The Server-Side Request Forgery vulnerability allows attackers to access internal services, steal credentials, scan your internal network, and exfiltrate sensitive data through crafted HTML:

<!-- Malicious HTML submitted to your PDF generator -->
<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe>
<img src="http://internal-database:5432/admin"/>
HTML

When wkhtmltopdf renders this HTML, it fetches these URLs from your server's network context, bypassing firewalls and security controls.

Affected Wrapper Libraries

Every .NET wrapper bundles or shells out to the same wkhtmltopdf native binary, so they all inherit its CVE exposure regardless of how active the wrapper itself is:

Wrapper LibraryLatest NuGetSecurity Risk
DinkToPdf1.0.8 (April 2017) - abandonedInherits CVE-2022-35583
Rotativa.AspNetCore (webgio fork)1.4.0 (Nov 2023) - wrapper updated, binary frozenInherits CVE-2022-35583
TuesPechkin2.1.1 (Jan 2015) - abandonedInherits CVE-2022-35583
Haukcode.WkHtmlToPdfDotNet (formerly WkHtmlToPdf-DotNet)1.5.95 (Oct 2024) - wrapper updated, binary frozenInherits CVE-2022-35583
NReco.PdfGeneratorwrapper updated, bundles wkhtmltopdfInherits CVE-2022-35583

If you use any of these libraries, your application is exposed to CVE-2022-35583 unless you sanitize all HTML input.

IronPDF vs wkhtmltopdf: Feature Comparison

Understanding the architectural differences helps technical decision-makers evaluate the migration investment:

FeaturewkhtmltopdfIronPDF
LicensingLGPLv3 (Free)Commercial
Rendering EngineQt 4.8 + QtWebKit (Qt 4.8 EOL 2015)Current Chromium engine
Security VulnerabilitiesCVE-2022-35583 (CVSS 9.8) unpatched, disputedNo critical CVEs reported
Active MaintenanceGitHub repo archived Jan 2, 2023; last release June 2020Actively maintained with regular releases
Support for Modern Web StandardsLimited (Broken flexbox, no CSS Grid)Supported
Integration and SupportLimited to community forumsExtensive documentation and dedicated support
CSS Grid❌ Not supported✅ Supported
Flexbox⚠ Broken✅ Supported
ES6+ JavaScript❌ Not supported✅ Supported
Async/Await❌ Not supported✅ Supported
PDF Manipulation❌ Not supported✅ Supported
Digital Signatures❌ Not supported✅ Supported
PDF/A Compliance❌ Not supported✅ Supported

Quick Start: wkhtmltopdf to IronPDF Migration

The migration can begin immediately with these foundational steps.

Step 1: Remove wkhtmltopdf Packages and Binaries

Remove all wkhtmltopdf wrapper packages:

# Remove wkhtmltopdf wrapper (whichever you're using)
dotnet remove package Haukcode.WkHtmlToPdfDotNet
dotnet remove package DinkToPdf
dotnet remove package TuesPechkin
dotnet remove package Rotativa
dotnet remove package Rotativa.AspNetCore
dotnet remove package NReco.PdfGenerator

# Remove wkhtmltopdf binary from your deployment
# Delete wkhtmltopdf.exe, wkhtmltox.dll, etc.
SHELL

Step 2: Install IronPDF

# Add IronPDF (secure, modern alternative)
dotnet add package IronPdf
SHELL

Step 3: Update Namespaces

Replace wkhtmltopdf namespaces with the IronPDF namespace:

// Before (wkhtmltopdf)
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;

// After (IronPDF)
using IronPdf;

Step 4: Initialize License

Add license initialization at application startup:

IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";

Code Migration Examples

Converting HTML to PDF

The most fundamental operation reveals the complexity difference between these .NET PDF approaches.

wkhtmltopdf Approach:

// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;

class Program
{
    static void Main()
    {
        var converter = new SynchronizedConverter(new PdfTools());
        var doc = new HtmlToPdfDocument()
        {
            GlobalSettings = {
                ColorMode = ColorMode.Color,
                Orientation = Orientation.Portrait,
                PaperSize = PaperKind.A4
            },
            Objects = {
                new ObjectSettings()
                {
                    HtmlContent = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>"
                }
            }
        };
        byte[] pdf = converter.Convert(doc);
        File.WriteAllBytes("output.pdf", pdf);
    }
}

IronPDF Approach:

// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF from HTML.</p>");
        pdf.SaveAs("output.pdf");
    }
}

wkhtmltopdf requires creating a SynchronizedConverter with PdfTools, constructing an HtmlToPdfDocument with GlobalSettings and Objects, setting properties like ColorMode, Orientation, and PaperSize, calling converter.Convert() to get raw bytes, and manually writing to a file with File.WriteAllBytes().

IronPDF eliminates this ceremony entirely - create a ChromePdfRenderer, call RenderHtmlAsPdf(), and use the built-in SaveAs() method.

For advanced HTML-to-PDF scenarios, see the HTML to PDF conversion guide.

Converting URLs to PDF

URL-to-PDF conversion shows similar complexity patterns.

wkhtmltopdf Approach:

// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;

class Program
{
    static void Main()
    {
        var converter = new SynchronizedConverter(new PdfTools());
        var doc = new HtmlToPdfDocument()
        {
            GlobalSettings = {
                ColorMode = ColorMode.Color,
                Orientation = Orientation.Portrait,
                PaperSize = PaperKind.A4
            },
            Objects = {
                new ObjectSettings()
                {
                    Page = "https://www.example.com"
                }
            }
        };
        byte[] pdf = converter.Convert(doc);
        File.WriteAllBytes("webpage.pdf", pdf);
    }
}

IronPDF Approach:

// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
        pdf.SaveAs("webpage.pdf");
    }
}

wkhtmltopdf uses the Page property in ObjectSettings to specify a URL, requiring the same document construction pattern. IronPDF provides a dedicated RenderUrlAsPdf() method that clearly expresses intent.

Explore the URL to PDF documentation for authentication and custom header options.

Custom Settings: HTML Files with Page Configuration

Configuring orientation, margins, and paper size requires different approaches.

wkhtmltopdf Approach:

// NuGet: Install-Package Haukcode.WkHtmlToPdfDotNet
using Haukcode.WkHtmlToPdfDotNet;
using Haukcode.WkHtmlToPdfDotNet.Contracts;
using System.IO;

class Program
{
    static void Main()
    {
        var converter = new SynchronizedConverter(new PdfTools());
        var doc = new HtmlToPdfDocument()
        {
            GlobalSettings = {
                ColorMode = ColorMode.Color,
                Orientation = Orientation.Landscape,
                PaperSize = PaperKind.A4,
                Margins = new MarginSettings() { Top = 10, Bottom = 10, Left = 10, Right = 10 }
            },
            Objects = {
                new ObjectSettings()
                {
                    Page = "input.html",
                    WebSettings = { DefaultEncoding = "utf-8" }
                }
            }
        };
        byte[] pdf = converter.Convert(doc);
        File.WriteAllBytes("custom-output.pdf", pdf);
    }
}

IronPDF Approach:

// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
        renderer.RenderingOptions.MarginTop = 10;
        renderer.RenderingOptions.MarginBottom = 10;
        renderer.RenderingOptions.MarginLeft = 10;
        renderer.RenderingOptions.MarginRight = 10;
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
        
        var pdf = renderer.RenderHtmlFileAsPdf("input.html");
        pdf.SaveAs("custom-output.pdf");
    }
}

wkhtmltopdf nests settings inside GlobalSettings and Objects, with MarginSettings as a separate object. IronPDF provides direct RenderingOptions properties with clear names like PaperOrientation, MarginTop, and PaperSize.

wkhtmltopdf API to IronPDF Mapping Reference

This mapping accelerates migration by showing direct API equivalents:

CLI to IronPDF Mapping

wkhtmltopdf CLI OptionIronPDF Equivalent
wkhtmltopdf input.html output.pdfrenderer.RenderHtmlFileAsPdf()
wkhtmltopdf URL output.pdfrenderer.RenderUrlAsPdf()
--page-size A4RenderingOptions.PaperSize = PdfPaperSize.A4
--page-size LetterRenderingOptions.PaperSize = PdfPaperSize.Letter
--orientation LandscapeRenderingOptions.PaperOrientation = Landscape
--margin-top 10mmRenderingOptions.MarginTop = 10
--margin-bottom 10mmRenderingOptions.MarginBottom = 10
--margin-left 10mmRenderingOptions.MarginLeft = 10
--margin-right 10mmRenderingOptions.MarginRight = 10
--header-html header.htmlRenderingOptions.HtmlHeader
--footer-center "[page]"{page} placeholder
--footer-center "[toPage]"{total-pages} placeholder
--enable-javascriptEnabled by default
--javascript-delay 500RenderingOptions.WaitFor.RenderDelay = 500
--dpi 300RenderingOptions.Dpi = 300
--grayscaleRenderingOptions.GrayScale = true

C# Wrapper API Mapping

wkhtmltopdf WrapperIronPDF
SynchronizedConverterChromePdfRenderer
HtmlToPdfDocumentRenderingOptions
GlobalSettings.Outpdf.SaveAs()
GlobalSettings.PaperSizeRenderingOptions.PaperSize
GlobalSettings.OrientationRenderingOptions.PaperOrientation
GlobalSettings.MarginsRenderingOptions.Margin*
ObjectSettings.PageRenderHtmlFileAsPdf()
ObjectSettings.HtmlContentRenderHtmlAsPdf()
converter.Convert(doc)renderer.RenderHtmlAsPdf()

Placeholder Syntax Migration

wkhtmltopdf PlaceholderIronPDF Placeholder
[page]{page}
[toPage]{total-pages}
[date]{date}
[time]{time}
[title]{html-title}
[url]{url}

Common Migration Issues and Solutions

Issue 1: Header/Footer Placeholder Syntax

wkhtmltopdf: Uses square bracket syntax like [page] and [toPage].

Solution: Update to IronPDF's curly brace placeholders:

// Before (wkhtmltopdf)
FooterSettings = { Left = "Page [page] of [toPage]" }

// After (IronPDF)
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = "<div style='text-align:left;'>Page {page} of {total-pages}</div>",
    MaxHeight = 25
};

Issue 2: JavaScript Delay Configuration

wkhtmltopdf: Uses JavascriptDelay property with limited reliability.

Solution: IronPDF provides multiple options:

renderer.RenderingOptions.EnableJavaScript = true;

// Option 1: Fixed delay
renderer.RenderingOptions.WaitFor.RenderDelay(500);

// Option 2: Wait for specific element (more reliable)
renderer.RenderingOptions.WaitFor.HtmlElementById("content-loaded");

// Option 3: Wait for JavaScript condition
renderer.RenderingOptions.WaitFor.JavaScript("window.renderComplete === true");

Issue 3: Modern CSS Not Rendering

Symptom: CSS Grid and Flexbox layouts render incorrectly in wkhtmltopdf.

Solution: IronPDF's Chromium engine handles modern CSS correctly:

// This CSS now works with IronPDF
var html = @"
<style>
    .grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
    .flex { display: flex; justify-content: space-between; align-items: center; }
</style>
<div class='grid'>
    <div>Column 1</div>
    <div>Column 2</div>
    <div>Column 3</div>
</div>";

var pdf = renderer.RenderHtmlAsPdf(html);

Issue 4: Synchronous vs Asynchronous Rendering

wkhtmltopdf: Wrappers are synchronous and block threads.

Solution: IronPDF supports async rendering:

public async Task<byte[]> GeneratePdfAsync(string html)
{
    var renderer = new ChromePdfRenderer();
    var pdf = await renderer.RenderHtmlAsPdfAsync(html);
    return pdf.BinaryData;
}

wkhtmltopdf Migration Checklist

Pre-Migration Tasks

Audit your codebase to identify all wkhtmltopdf usage:

# Find all wkhtmltopdf references
grep -r "Haukcode.WkHtmlToPdfDotNet\|WkHtmlToPdfDotNet\|DinkToPdf\|TuesPechkin\|Rotativa\|NReco.PdfGenerator" --include="*.cs" .
grep -r "wkhtmltopdf" --include="*.yml" --include="*.yaml" --include="Dockerfile" .
SHELL

Locate and document wkhtmltopdf binary files for removal. Document current settings (paper size, margins, headers/footers).

Code Update Tasks

  1. Remove all wkhtmltopdf wrapper NuGet packages
  2. Remove wkhtmltopdf binaries (wkhtmltopdf.exe, wkhtmltox.dll)
  3. Install IronPDF NuGet package
  4. Update namespace imports from Haukcode.WkHtmlToPdfDotNet (or the wrapper you used) to IronPdf
  5. Replace SynchronizedConverter with ChromePdfRenderer
  6. Convert HtmlToPdfDocument patterns to direct rendering methods
  7. Update GlobalSettings configurations to RenderingOptions
  8. Convert margin configurations from MarginSettings to individual properties
  9. Update placeholder syntax ([page]{page}, [toPage]{total-pages})
  10. Add IronPDF license initialization at startup

Post-Migration Testing

After migration, verify these aspects:

  • Visual comparison of PDF output (should improve with modern CSS support)
  • Verify modern CSS rendering (CSS Grid and Flexbox now work)
  • Test JavaScript-heavy pages
  • Security scan to confirm no wkhtmltopdf binaries remain
  • Load test for performance comparison

Security Verification

# Scan for any remaining wkhtmltopdf artifacts
find /var/www/ -name "*wkhtmlto*" 2>/dev/null
find /usr/local/bin/ -name "*wkhtmlto*" 2>/dev/null
docker images | grep wkhtmltopdf

# Check if any process is still using it
ps aux | grep wkhtmltopdf
SHELL

Key Benefits of Migrating to IronPDF

Moving from wkhtmltopdf to IronPDF provides several critical advantages:

Security: CVE-2022-35583 and all wkhtmltopdf vulnerabilities are eliminated. IronPDF has no known CVEs and receives regular security updates.

Modern Rendering Engine: IronPDF uses the current Chromium engine, ensuring full CSS3, CSS Grid, Flexbox, and ES6+ JavaScript support. Modern frameworks render correctly.

Simplified API: Direct rendering methods replace document construction patterns. Built-in SaveAs() methods eliminate manual byte handling.

Extended Capabilities: PDF manipulation, digital signatures, PDF/A compliance, watermarks, and merge/split operations are built-in features that wkhtmltopdf couldn't provide.

Active Development: IronPDF's regular updates track current .NET releases, so modern .NET and C# language versions are supported as they ship.

Async Support: Prevent thread blocking in high-load web applications with native async/await support.

Please note: DinkToPdf, NReco, Rotativa, TuesPechkin, and wkhtmltopdf are registered trademarks of their respective owners. This site is not affiliated with, endorsed by, or sponsored by DinkToPdf, NReco, Rotativa, TuesPechkin, or wkhtmltopdf. All product names, logos, and brands are property of their respective owners. Comparisons are for informational purposes only and reflect publicly available information at the time of writing.
Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...
Read More

Related Articles

Key in blue circle

Get your free 30-day Trial Key instantly.

Your trial license will be sent to your email address

No limitations. 100% unlocked. No credit card.

bullet_checkedNo credit card or account creation requiredNo limitations. 100% unlocked. No credit card.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
Book your free Live Demo
Booking Badge

Trusted by Millions of Engineers Worldwide

Iron Software's customer logos
Get Your No-Obligation Consult
Complete the form below or email sales@ironsoftware.com
Your details will always be kept confidential.
Trusted by Millions of Engineers Worldwide
Iron Software's customer logos
Get your free 30-day Trial Key instantly.
No credit card or account creation required