From df75bb52cf1ae37163c1a2b7ef9b56ca9a1ffa3e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 12 Oct 2026 19:06:34 +0000 Subject: [PATCH 1/5] Initial plan From 0a48865bdfd5d8af4d4c54b12988919d8f14bf17 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 12 Oct 2026 19:07:53 +0000 Subject: [PATCH 2/5] Harden AstSchemaParser XML parsing against XXE Co-authored-by: fupacat <595487+fupacat@users.noreply.github.com> --- .../io/github/fupacat/AstSchemaParser.java | 3 +++ .../github/fupacat/AstSchemaParserTest.java | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/tsql-scriptdom-astgen/src/main/java/io/github/fupacat/AstSchemaParser.java b/tsql-scriptdom-astgen/src/main/java/io/github/fupacat/AstSchemaParser.java index 61ce073..c86ad1f 100644 --- a/tsql-scriptdom-astgen/src/main/java/io/github/fupacat/AstSchemaParser.java +++ b/tsql-scriptdom-astgen/src/main/java/io/github/fupacat/AstSchemaParser.java @@ -1,12 +1,15 @@ package io.github.fupacat; import java.io.InputStream; +import javax.xml.XMLConstants; public class AstSchemaParser { // TRACEABILITY_MAPPING: REQ-001 public AstModel parse(InputStream inputStream) throws Exception { javax.xml.parsers.DocumentBuilderFactory factory = javax.xml.parsers.DocumentBuilderFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); javax.xml.parsers.DocumentBuilder builder = factory.newDocumentBuilder(); org.w3c.dom.Document doc = builder.parse(inputStream); doc.getDocumentElement().normalize(); diff --git a/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java b/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java index fc64f08..8f0ac35 100644 --- a/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java +++ b/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java @@ -1,8 +1,11 @@ package io.github.fupacat; import org.junit.jupiter.api.Test; +import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; public class AstSchemaParserTest { @@ -20,4 +23,24 @@ public void testParseAstXml() throws Exception { assertThat(model.interfaces).isNotEmpty(); } } + + // TRACEABILITY_MAPPING: REQ-001 + @Test + public void testRejectsDocTypeDeclaration() { + AstSchemaParser parser = new AstSchemaParser(); + String xml = """ + + ]> + + + + + + """; + InputStream inputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); + + assertThatThrownBy(() -> parser.parse(inputStream)) + .isInstanceOf(org.xml.sax.SAXException.class); + } } From 34c1a77f403c40dc7f2e50a2bfe148a006c86195 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 12 Oct 2026 19:09:24 +0000 Subject: [PATCH 3/5] Relax parser security test for JAXP portability Co-authored-by: fupacat <595487+fupacat@users.noreply.github.com> --- .../src/test/java/io/github/fupacat/AstSchemaParserTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java b/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java index 8f0ac35..7c59570 100644 --- a/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java +++ b/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java @@ -41,6 +41,6 @@ public void testRejectsDocTypeDeclaration() { InputStream inputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); assertThatThrownBy(() -> parser.parse(inputStream)) - .isInstanceOf(org.xml.sax.SAXException.class); + .isInstanceOfAny(org.xml.sax.SAXException.class, javax.xml.parsers.ParserConfigurationException.class); } } From b7dfb4529bb12389cda0b2e7a18cf9805c6b78b7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 12 Oct 2026 19:10:44 +0000 Subject: [PATCH 4/5] Narrow DOCTYPE rejection assertion to SAXException Co-authored-by: fupacat <595487+fupacat@users.noreply.github.com> --- .../src/test/java/io/github/fupacat/AstSchemaParserTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java b/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java index 7c59570..8f0ac35 100644 --- a/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java +++ b/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java @@ -41,6 +41,6 @@ public void testRejectsDocTypeDeclaration() { InputStream inputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); assertThatThrownBy(() -> parser.parse(inputStream)) - .isInstanceOfAny(org.xml.sax.SAXException.class, javax.xml.parsers.ParserConfigurationException.class); + .isInstanceOf(org.xml.sax.SAXException.class); } } From ec96ca57bcc01ee07ba495dc51e9988226330346 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 12 Oct 2026 19:12:00 +0000 Subject: [PATCH 5/5] Strengthen DOCTYPE rejection test assertion Co-authored-by: fupacat <595487+fupacat@users.noreply.github.com> --- .../src/test/java/io/github/fupacat/AstSchemaParserTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java b/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java index 8f0ac35..18597aa 100644 --- a/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java +++ b/tsql-scriptdom-astgen/src/test/java/io/github/fupacat/AstSchemaParserTest.java @@ -41,6 +41,7 @@ public void testRejectsDocTypeDeclaration() { InputStream inputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); assertThatThrownBy(() -> parser.parse(inputStream)) - .isInstanceOf(org.xml.sax.SAXException.class); + .isInstanceOf(org.xml.sax.SAXParseException.class) + .hasMessageContaining("DOCTYPE"); } }