diff --git a/generate-html.js b/generate-html.js
index 88254b0..21d97ad 100644
--- a/generate-html.js
+++ b/generate-html.js
@@ -1,3 +1,5 @@
+const { escapeAttribute } = require("entities/lib/escape.js");
+
const DEFAULT_ATTRIBUTES = {
// loading: "lazy",
// decoding: "async",
@@ -128,6 +130,10 @@ function generateObject(metadata, attributes = {}, options = {}) {
function mapObjectToHTML(tagName, attrs = {}) {
let attrHtml = Object.entries(attrs).map(entry => {
let [key, value] = entry;
+ if(key === "alt") {
+ return `${key}="${value ? escapeAttribute(value) : ""}"`;
+ }
+
return `${key}="${value}"`;
}).join(" ");
diff --git a/package.json b/package.json
index 3bf90fe..2e20f97 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
"dependencies": {
"@11ty/eleventy-fetch": "^3.0.0",
"debug": "^4.3.4",
+ "entities": "^4.4.0",
"image-size": "^1.0.2",
"p-queue": "^6.6.2",
"sharp": "^0.31.3"
diff --git a/test/test-markup.js b/test/test-markup.js
index ca710d5..e6ff05d 100644
--- a/test/test-markup.js
+++ b/test/test-markup.js
@@ -245,3 +245,14 @@ test("Image markup (animated gif, two formats)", async t => {
let e = t.throws(() => generateHTML(results, { alt: "" }));
t.true(e.message.startsWith("Could not find the lowest "));
});
+
+test("Image markup (escaped `alt`)", async t => {
+ let results = await eleventyImage("./test/bio-2017.jpg", {
+ formats: ["auto"],
+ dryRun: true,
+ });
+
+ t.is(generateHTML(results, {
+ alt: "This is a \"test"
+ }), ``);
+});