Skip to content

Commit

Permalink
Fix vulnerability on unescaped HTML attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonioVdlC committed Jun 17, 2024
1 parent 5625e19 commit eb0adb4
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 0 deletions.
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"vitest": "^0.9.3"
},
"dependencies": {
"html-element-attributes": "^3.4.0",
"html-es6cape": "^2.0.0"
}
}
21 changes: 21 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
// Inspired on http://www.2ality.com/2015/01/template-strings-html.html#comment-2078932192

import escape from "html-es6cape";
import { htmlElementAttributes } from "html-element-attributes";

const attributes = Object.values(htmlElementAttributes).flat();
function endsWithUnescapedAttribute(acc: string): boolean {
return attributes.some((attribute) => acc.endsWith(`${attribute}=`));
}

function htmlTemplateTag(
literals: TemplateStringsArray,
Expand All @@ -18,6 +24,21 @@ function htmlTemplateTag(
subst = escape(subst);
}

/*
* If the interpolation is preceded by an unescaped attribute, we need to
* add quotes around the substitution to avoid XSS attacks.
*
* ```
* const foo = "Alt onload=alert(1)";
* html`<img src="..." alt=${foo} />`
* => <img src="..." alt=Alt onload=alert(1) />
* ```
*/
if (endsWithUnescapedAttribute(acc)) {
acc += '"';
lit = '"' + lit;
}

return acc + subst + lit;
});
}
Expand Down
17 changes: 17 additions & 0 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,21 @@ describe("html-template-tag", () => {
</div>`
);
});

it("should add quotes around alt attribute", () => {
const src = "https://example.com/image.jpg";
const alt = "Alt onload=alert(1)";
console.log(html`<img src="${src}" alt=${alt} />`);
expect(html`<img src="${src}" alt=${alt} />`).toEqual(
`<img src="https://example.com/image.jpg" alt="Alt onload=alert(1)" />`
);
});

it("should not add quotes around alt attribute if they are already present", () => {
const src = "https://example.com/image.jpg";
const alt = "Alt onload=alert(1)";
expect(html`<img src="${src}" alt="${alt}" />`).toEqual(
`<img src="https://example.com/image.jpg" alt="Alt onload=alert(1)" />`
);
});
});

0 comments on commit eb0adb4

Please sign in to comment.