diff --git a/.changeset/blue-dragons-see.md b/.changeset/blue-dragons-see.md
new file mode 100644
index 0000000000..fb412ce4ed
--- /dev/null
+++ b/.changeset/blue-dragons-see.md
@@ -0,0 +1,14 @@
+---
+"marko": patch
+"@marko/runtime-tags": patch
+---
+
+Fix escaping issue for dynamic text interpolation inside `"}
+```
+
+Note that `script` and `style` there should _never_ render unsanitized user defined values, regardless of wether or not the closing tag is escaped, since these are conceptually just "eval".
diff --git a/.changeset/frank-memes-knock.md b/.changeset/frank-memes-knock.md
new file mode 100644
index 0000000000..25e56dc10d
--- /dev/null
+++ b/.changeset/frank-memes-knock.md
@@ -0,0 +1,13 @@
+---
+"marko": patch
+"@marko/runtime-tags": patch
+---
+
+Fix escaping for `` tag.
+Previously this tag relied on normal xml escaping which looks for `<`.
+This PR updates to have a special escape for `` tags that replaces `>` instead.
+
+```marko
+// Previously incorrectly escaped.
+${">Uh oh"}
+```
diff --git a/packages/runtime-class/src/runtime/html/helpers/escape-comment-placeholder.js b/packages/runtime-class/src/runtime/html/helpers/escape-comment-placeholder.js
new file mode 100644
index 0000000000..350a007a0a
--- /dev/null
+++ b/packages/runtime-class/src/runtime/html/helpers/escape-comment-placeholder.js
@@ -0,0 +1,17 @@
+"use strict";
+const unsafeCharsReg = />/g;
+const replaceMatch = () => ">";
+const escape = (str) =>
+ unsafeCharsReg.test(str) ? str.replace(unsafeCharsReg, replaceMatch) : str;
+
+/**
+ * Escapes content placed inside an tag.
+ *
+ * For example:
+ * ${userInput}
+ *
+ * Without escaping, a value of `>`,
- ]);
+ const { file } = path.hub;
+ const nodes = [writeHTML``);
+ path.replaceWithMultiple(nodes.filter(Boolean));
} else {
const templateQuasis = [];
const templateExpressions = [];
diff --git a/packages/runtime-class/test/render/fixtures/escape-comment/expected.html b/packages/runtime-class/test/render/fixtures/escape-comment/expected.html
new file mode 100644
index 0000000000..90eb036ed8
--- /dev/null
+++ b/packages/runtime-class/test/render/fixtures/escape-comment/expected.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/runtime-class/test/render/fixtures/escape-comment/template.marko b/packages/runtime-class/test/render/fixtures/escape-comment/template.marko
new file mode 100644
index 0000000000..019e855e8a
--- /dev/null
+++ b/packages/runtime-class/test/render/fixtures/escape-comment/template.marko
@@ -0,0 +1 @@
+${input.text}
diff --git a/packages/runtime-class/test/render/fixtures/escape-comment/test.js b/packages/runtime-class/test/render/fixtures/escape-comment/test.js
new file mode 100644
index 0000000000..eb04215fef
--- /dev/null
+++ b/packages/runtime-class/test/render/fixtures/escape-comment/test.js
@@ -0,0 +1,3 @@
+exports.templateData = {
+ text: "-->",
+};
diff --git a/packages/runtime-class/test/render/fixtures/escape-comment/vdom-expected.html b/packages/runtime-class/test/render/fixtures/escape-comment/vdom-expected.html
new file mode 100644
index 0000000000..b2c6a1f288
--- /dev/null
+++ b/packages/runtime-class/test/render/fixtures/escape-comment/vdom-expected.html
@@ -0,0 +1 @@
+"-->
diff --git a/packages/runtime-class/test/render/fixtures/escape-script-case/expected.html b/packages/runtime-class/test/render/fixtures/escape-script-case/expected.html
new file mode 100644
index 0000000000..50ec8d57c7
--- /dev/null
+++ b/packages/runtime-class/test/render/fixtures/escape-script-case/expected.html
@@ -0,0 +1,3 @@
+
{"name":"Evil </SCRIPT>"}
\ No newline at end of file
diff --git a/packages/runtime-class/test/render/fixtures/escape-script-case/template.marko b/packages/runtime-class/test/render/fixtures/escape-script-case/template.marko
new file mode 100644
index 0000000000..4ff4986f79
--- /dev/null
+++ b/packages/runtime-class/test/render/fixtures/escape-script-case/template.marko
@@ -0,0 +1,4 @@
+
+
${JSON.stringify(input.foo)}
\ No newline at end of file
diff --git a/packages/runtime-class/test/render/fixtures/escape-script-case/test.js b/packages/runtime-class/test/render/fixtures/escape-script-case/test.js
new file mode 100644
index 0000000000..c0a15e5cc7
--- /dev/null
+++ b/packages/runtime-class/test/render/fixtures/escape-script-case/test.js
@@ -0,0 +1,5 @@
+exports.templateData = {
+ foo: {
+ name: "Evil ",
+ },
+};
diff --git a/packages/runtime-class/test/render/fixtures/escape-script-case/vdom-expected.html b/packages/runtime-class/test/render/fixtures/escape-script-case/vdom-expected.html
new file mode 100644
index 0000000000..591eb6cbd5
--- /dev/null
+++ b/packages/runtime-class/test/render/fixtures/escape-script-case/vdom-expected.html
@@ -0,0 +1,4 @@
+\"};\n"
+
+ "{\"name\":\"Evil \"}"
diff --git a/packages/runtime-class/test/render/fixtures/escape-style-case/expected.html b/packages/runtime-class/test/render/fixtures/escape-style-case/expected.html
new file mode 100644
index 0000000000..067d80802e
--- /dev/null
+++ b/packages/runtime-class/test/render/fixtures/escape-style-case/expected.html
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/packages/runtime-class/test/render/fixtures/escape-style-case/template.marko b/packages/runtime-class/test/render/fixtures/escape-style-case/template.marko
new file mode 100644
index 0000000000..37c1ff9d51
--- /dev/null
+++ b/packages/runtime-class/test/render/fixtures/escape-style-case/template.marko
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/packages/runtime-class/test/render/fixtures/escape-style-case/test.js b/packages/runtime-class/test/render/fixtures/escape-style-case/test.js
new file mode 100644
index 0000000000..49ffcd626c
--- /dev/null
+++ b/packages/runtime-class/test/render/fixtures/escape-style-case/test.js
@@ -0,0 +1,3 @@
+exports.templateData = {
+ color: '',
+};
diff --git a/packages/runtime-class/test/render/fixtures/escape-style-case/vdom-expected.html b/packages/runtime-class/test/render/fixtures/escape-style-case/vdom-expected.html
new file mode 100644
index 0000000000..e44cc7224b
--- /dev/null
+++ b/packages/runtime-class/test/render/fixtures/escape-style-case/vdom-expected.html
@@ -0,0 +1,2 @@
+;\n }\n"
diff --git a/packages/runtime-tags/src/__tests__/fixtures/html-comment-counter/__snapshots__/html.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/html-comment-counter/__snapshots__/html.expected/template.js
index 37d8b6e5c1..2c14854fa5 100644
--- a/packages/runtime-tags/src/__tests__/fixtures/html-comment-counter/__snapshots__/html.expected/template.js
+++ b/packages/runtime-tags/src/__tests__/fixtures/html-comment-counter/__snapshots__/html.expected/template.js
@@ -3,7 +3,7 @@ export default _._template("__tests__/template.marko", input => {
_._scope_reason();
const $scope0_id = _._scope_id();
let count = 0;
- _._html(`