diff --git a/src/core/catalog.js b/src/core/catalog.js
index 6c768e856..08d80e01d 100644
--- a/src/core/catalog.js
+++ b/src/core/catalog.js
@@ -915,6 +915,22 @@ class Catalog {
     return shadow(this, "attachments", attachments);
   }
 
+  get xfaImages() {
+    const obj = this._catDict.get("Names");
+    let xfaImages = null;
+
+    if (obj instanceof Dict && obj.has("XFAImages")) {
+      const nameTree = new NameTree(obj.getRaw("XFAImages"), this.xref);
+      for (const [key, value] of nameTree.getAll()) {
+        if (!xfaImages) {
+          xfaImages = new Dict(this.ref);
+        }
+        xfaImages.set(key, value);
+      }
+    }
+    return shadow(this, "xfaImages", xfaImages);
+  }
+
   _collectJavaScript() {
     const obj = this._catDict.get("Names");
     let javaScript = null;
diff --git a/src/core/document.js b/src/core/document.js
index c9ced6ca2..1e5e18069 100644
--- a/src/core/document.js
+++ b/src/core/document.js
@@ -869,6 +869,28 @@ class PDFDocument {
     return null;
   }
 
+  async loadXfaImages() {
+    const xfaImagesDict = await this.pdfManager.ensureCatalog("xfaImages");
+    if (!xfaImagesDict) {
+      return;
+    }
+
+    const keys = xfaImagesDict.getKeys();
+    const objectLoader = new ObjectLoader(xfaImagesDict, keys, this.xref);
+    await objectLoader.load();
+
+    const xfaImages = new Map();
+    for (const key of keys) {
+      const stream = xfaImagesDict.get(key);
+      if (!isStream(stream)) {
+        continue;
+      }
+      xfaImages.set(key, stream.getBytes());
+    }
+
+    this.xfaFactory.setImages(xfaImages);
+  }
+
   async loadXfaFonts(handler, task) {
     const acroForm = await this.pdfManager.ensureCatalog("acroForm");
     if (!acroForm) {
diff --git a/src/core/pdf_manager.js b/src/core/pdf_manager.js
index c0f194599..4b5df1a8f 100644
--- a/src/core/pdf_manager.js
+++ b/src/core/pdf_manager.js
@@ -77,6 +77,10 @@ class BasePdfManager {
     return this.pdfDocument.loadXfaFonts(handler, task);
   }
 
+  loadXfaImages() {
+    return this.pdfDocument.loadXfaImages();
+  }
+
   serializeXfaData(annotationStorage) {
     return this.pdfDocument.serializeXfaData(annotationStorage);
   }
diff --git a/src/core/worker.js b/src/core/worker.js
index fd5740317..5b9164301 100644
--- a/src/core/worker.js
+++ b/src/core/worker.js
@@ -191,12 +191,15 @@ class WorkerMessageHandler {
       if (isPureXfa) {
         const task = new WorkerTask("loadXfaFonts");
         startWorkerTask(task);
-        await pdfManager
-          .loadXfaFonts(handler, task)
-          .catch(reason => {
-            // Ignore errors, to allow the document to load.
-          })
-          .then(() => finishWorkerTask(task));
+        await Promise.all([
+          pdfManager
+            .loadXfaFonts(handler, task)
+            .catch(reason => {
+              // Ignore errors, to allow the document to load.
+            })
+            .then(() => finishWorkerTask(task)),
+          pdfManager.loadXfaImages(),
+        ]);
       }
 
       const [numPages, fingerprints] = await Promise.all([
diff --git a/src/core/xfa/factory.js b/src/core/xfa/factory.js
index d1eb6652f..cc1d9143e 100644
--- a/src/core/xfa/factory.js
+++ b/src/core/xfa/factory.js
@@ -61,6 +61,10 @@ class XFAFactory {
     return this.dims.length;
   }
 
+  setImages(images) {
+    this.form[$globalData].images = images;
+  }
+
   setFonts(fonts) {
     this.form[$globalData].fontFinder = new FontFinder(fonts);
     const missingFonts = [];
diff --git a/src/core/xfa/template.js b/src/core/xfa/template.js
index 1e0c6c60b..75b2b8335 100644
--- a/src/core/xfa/template.js
+++ b/src/core/xfa/template.js
@@ -2932,56 +2932,58 @@ class Image extends StringObject {
   }
 
   [$toHTML]() {
-    if (this.href || !this[$content]) {
-      // TODO: href can be a Name referring to an internal stream
-      // containing a picture.
+    let buffer = this[$globalData].images.get(this.href);
+    if (!buffer && (this.href || !this[$content])) {
       // In general, we don't get remote data and use what we have
       // in the pdf itself, so no picture for non null href.
       return HTMLResult.EMPTY;
     }
 
-    // TODO: Firefox doesn't support natively tiff (and tif) format.
-    if (this.transferEncoding === "base64") {
-      const buffer = stringToBytes(atob(this[$content]));
-      const blob = new Blob([buffer], { type: this.contentType });
-      let style;
-      switch (this.aspect) {
-        case "fit":
-        case "actual":
-          // TODO: check what to do with actual.
-          // Normally we should return {auto, auto} for it but
-          // it implies some wrong rendering (see xfa_bug1716816.pdf).
-          break;
-        case "height":
-          style = {
-            width: "auto",
-            height: "100%",
-          };
-          break;
-        case "none":
-          style = {
-            width: "100%",
-            height: "100%",
-          };
-          break;
-        case "width":
-          style = {
-            width: "100%",
-            height: "auto",
-          };
-          break;
-      }
-      return HTMLResult.success({
-        name: "img",
-        attributes: {
-          class: ["xfaImage"],
-          style,
-          src: URL.createObjectURL(blob),
-        },
-      });
+    if (!buffer && this.transferEncoding === "base64") {
+      buffer = stringToBytes(atob(this[$content]));
     }
 
-    return HTMLResult.EMPTY;
+    if (!buffer) {
+      return HTMLResult.EMPTY;
+    }
+
+    // TODO: Firefox doesn't support natively tiff (and tif) format.
+    const blob = new Blob([buffer], { type: this.contentType });
+    let style;
+    switch (this.aspect) {
+      case "fit":
+      case "actual":
+        // TODO: check what to do with actual.
+        // Normally we should return {auto, auto} for it but
+        // it implies some wrong rendering (see xfa_bug1716816.pdf).
+        break;
+      case "height":
+        style = {
+          width: "auto",
+          height: "100%",
+        };
+        break;
+      case "none":
+        style = {
+          width: "100%",
+          height: "100%",
+        };
+        break;
+      case "width":
+        style = {
+          width: "100%",
+          height: "auto",
+        };
+        break;
+    }
+    return HTMLResult.success({
+      name: "img",
+      attributes: {
+        class: ["xfaImage"],
+        style,
+        src: URL.createObjectURL(blob),
+      },
+    });
   }
 }
 
diff --git a/test/pdfs/xfa_bug1718521_1.pdf.link b/test/pdfs/xfa_bug1718521_1.pdf.link
new file mode 100644
index 000000000..d2e7153f9
--- /dev/null
+++ b/test/pdfs/xfa_bug1718521_1.pdf.link
@@ -0,0 +1 @@
+https://bugzilla.mozilla.org/attachment.cgi?id=9229396
diff --git a/test/pdfs/xfa_bug1718521_2.pdf.link b/test/pdfs/xfa_bug1718521_2.pdf.link
new file mode 100644
index 000000000..1bd5f5c9d
--- /dev/null
+++ b/test/pdfs/xfa_bug1718521_2.pdf.link
@@ -0,0 +1 @@
+https://bugzilla.mozilla.org/attachment.cgi?id=9229409
diff --git a/test/pdfs/xfa_bug1718521_3.pdf.link b/test/pdfs/xfa_bug1718521_3.pdf.link
new file mode 100644
index 000000000..ee5150146
--- /dev/null
+++ b/test/pdfs/xfa_bug1718521_3.pdf.link
@@ -0,0 +1 @@
+https://bugzilla.mozilla.org/attachment.cgi?id=9229430
diff --git a/test/test_manifest.json b/test/test_manifest.json
index eaa1956e2..c644f4745 100644
--- a/test/test_manifest.json
+++ b/test/test_manifest.json
@@ -938,6 +938,30 @@
        "lastPage": 2,
        "type": "eq"
     },
+    {  "id": "xfa_bug1718521_1",
+       "file": "pdfs/xfa_bug1718521_1.pdf",
+       "md5": "9b89dd9e6a4c6c3258ca24debd806863",
+       "link": true,
+       "rounds": 1,
+       "enableXfa": true,
+       "type": "eq"
+    },
+    {  "id": "xfa_bug1718521_2",
+       "file": "pdfs/xfa_bug1718521_2.pdf",
+       "md5": "c23beb39e1c91a780da9d4b60cbd157f",
+       "link": true,
+       "rounds": 1,
+       "enableXfa": true,
+       "type": "eq"
+    },
+    {  "id": "xfa_bug1718521_3",
+       "file": "pdfs/xfa_bug1718521_3.pdf",
+       "md5": "5cc6fb1a65515518e3e64baa81e7a21e",
+       "link": true,
+       "rounds": 1,
+       "enableXfa": true,
+       "type": "eq"
+    },
     {  "id": "xfa_bug1718735",
        "file": "pdfs/xfa_bug1718735.pdf",
        "md5": "1001f5c02c026943cbd37f646725d82f",