This is an automated email from the ASF dual-hosted git repository.

luigidemasi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-kit.git

commit 909ac08593cc95400d5416ce72857a61d4c4834d
Author: Andrea Cosentino <[email protected]>
AuthorDate: Mon Nov 2 09:29:05 2026 +0100

    Fix #139: correct SafeConstructor rationale and add global-tag regression 
tests
    
    Address review feedback:
    - Correct the rationale. SnakeYAML 2.3 (pinned) already rejects custom 
global
      tags by default via UnTrustedTagInspector, so the previous commit 
overstated
      the risk: new Yaml() does not permit arbitrary type instantiation here.
      SafeConstructor is defense in depth -- it also removes arbitrary object
      construction and makes the parsers' data-only intent explicit -- not a fix
      for an open vulnerability.
    - Add regression tests (VersionResolverTest, CveParserTest) asserting a
      globally tagged type is never constructed: release parsing rejects the 
YAML,
      CVE parsing falls back to line-based extraction, and a construction canary
      stays untouched.
    
    Co-authored-by: Claude Opus 4.8 <[email protected]>
---
 .../kit/knowledge/indexer/VersionResolver.java     |  3 +-
 .../kit/knowledge/indexer/parser/CveParser.java    |  3 +-
 .../kit/knowledge/indexer/VersionResolverTest.java | 25 +++++++++++++++++
 .../knowledge/indexer/parser/CveParserTest.java    | 32 ++++++++++++++++++++++
 4 files changed, 61 insertions(+), 2 deletions(-)

diff --git 
a/knowledge/indexer/src/main/java/org/apache/camel/kit/knowledge/indexer/VersionResolver.java
 
b/knowledge/indexer/src/main/java/org/apache/camel/kit/knowledge/indexer/VersionResolver.java
index 2444eeb7..8522e82f 100644
--- 
a/knowledge/indexer/src/main/java/org/apache/camel/kit/knowledge/indexer/VersionResolver.java
+++ 
b/knowledge/indexer/src/main/java/org/apache/camel/kit/knowledge/indexer/VersionResolver.java
@@ -94,7 +94,8 @@ public class VersionResolver {
         }
 
         List<CamelRelease> releases = new ArrayList<>();
-        // Frontmatter is plain data (maps/lists/scalars); SafeConstructor 
refuses arbitrary type tags.
+        // Frontmatter is plain data. SnakeYAML 2.x already rejects custom 
global tags by default;
+        // SafeConstructor also strips arbitrary-object construction from this 
parser (defense in depth).
         Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
 
         // Only top-level release files (not subdirectories like q/, sb/, etc.)
diff --git 
a/knowledge/indexer/src/main/java/org/apache/camel/kit/knowledge/indexer/parser/CveParser.java
 
b/knowledge/indexer/src/main/java/org/apache/camel/kit/knowledge/indexer/parser/CveParser.java
index fd7e493f..c52adda2 100644
--- 
a/knowledge/indexer/src/main/java/org/apache/camel/kit/knowledge/indexer/parser/CveParser.java
+++ 
b/knowledge/indexer/src/main/java/org/apache/camel/kit/knowledge/indexer/parser/CveParser.java
@@ -328,7 +328,8 @@ public class CveParser {
     @SuppressWarnings("unchecked")
     private static Map<String, Object> parseYamlFrontmatter(String 
frontmatter) {
         try {
-            // Frontmatter is plain data; SafeConstructor refuses arbitrary 
type tags (!!type).
+            // Frontmatter is plain data. SnakeYAML 2.x already rejects custom 
global tags by default;
+            // SafeConstructor also strips arbitrary-object construction here 
(defense in depth).
             Object parsed = new Yaml(new SafeConstructor(new 
LoaderOptions())).load(frontmatter);
             return parsed instanceof Map ? (Map<String, Object>) parsed : null;
         } catch (Exception e) {
diff --git 
a/knowledge/indexer/src/test/java/org/apache/camel/kit/knowledge/indexer/VersionResolverTest.java
 
b/knowledge/indexer/src/test/java/org/apache/camel/kit/knowledge/indexer/VersionResolverTest.java
index 1e699ba3..90af7136 100644
--- 
a/knowledge/indexer/src/test/java/org/apache/camel/kit/knowledge/indexer/VersionResolverTest.java
+++ 
b/knowledge/indexer/src/test/java/org/apache/camel/kit/knowledge/indexer/VersionResolverTest.java
@@ -375,4 +375,29 @@ class VersionResolverTest {
         assertEquals("4.14", mapping.camelMinor());
         assertEquals("4.14.2", mapping.camelVersion());
     }
+
+    // ── 10. SafeConstructor rejects globally tagged frontmatter ─────────
+
+    /** Flips a flag if SnakeYAML ever constructs it; a SafeConstructor-backed 
parser must not. */
+    public static final class Canary {
+        static volatile boolean constructed = false;
+
+        public Canary() {
+            constructed = true;
+        }
+    }
+
+    @Test
+    void rejectsGloballyTaggedReleaseFrontmatterWithoutConstructing() throws 
Exception {
+        Canary.constructed = false;
+        Path releasesDir = 
Files.createDirectories(tempDir.resolve("content/releases"));
+        Files.writeString(releasesDir.resolve("release-4.14.0.md"),
+                "---\ncategory: camel\ndate: 2026-01-15\npwn: !!" + 
Canary.class.getName() + " {}\n---\nBody.\n");
+
+        // SafeConstructor refuses the global tag during composition, before 
any construction.
+        assertThrows(org.yaml.snakeyaml.error.YAMLException.class,
+                () -> VersionResolver.parseReleases(tempDir));
+        assertFalse(Canary.constructed,
+                "SafeConstructor must not instantiate a globally tagged type 
in release frontmatter");
+    }
 }
diff --git 
a/knowledge/indexer/src/test/java/org/apache/camel/kit/knowledge/indexer/parser/CveParserTest.java
 
b/knowledge/indexer/src/test/java/org/apache/camel/kit/knowledge/indexer/parser/CveParserTest.java
index 99e50723..2d7c4b29 100644
--- 
a/knowledge/indexer/src/test/java/org/apache/camel/kit/knowledge/indexer/parser/CveParserTest.java
+++ 
b/knowledge/indexer/src/test/java/org/apache/camel/kit/knowledge/indexer/parser/CveParserTest.java
@@ -51,4 +51,36 @@ class CveParserTest {
         assertTrue(ranges.contains("3.0.0-3.21.4"));
         assertTrue(ranges.contains("4.0.0-4.0.4"));
     }
+
+    /** Flips a flag if SnakeYAML ever constructs it; a SafeConstructor-backed 
parser must not. */
+    public static final class Canary {
+        static volatile boolean constructed = false;
+
+        public Canary() {
+            constructed = true;
+        }
+    }
+
+    @Test
+    void cveGlobalTagFallsBackToLineExtractionWithoutConstructing() {
+        Canary.constructed = false;
+        String content = "---\n"
+                         + "cve: CVE-2099-0001\n"
+                         + "severity: HIGH\n"
+                         + "summary: \"Canary advisory\"\n"
+                         + "pwn: !!" + Canary.class.getName() + " {}\n"
+                         + "fixed: \"4.0.4, 3.21.4\"\n"
+                         + "---\n"
+                         + "Body referencing CAMEL-12345.\n";
+
+        // The global tag makes SafeConstructor throw; parseYamlFrontmatter 
catches it and falls
+        // back to line-based regex extraction, so the advisory still parses 
and nothing is constructed.
+        CveParser.CveAdvisory cve = CveParser.parse(content);
+
+        assertFalse(Canary.constructed,
+                "SafeConstructor must not instantiate a globally tagged type 
in CVE frontmatter");
+        assertEquals("CVE-2099-0001", cve.cveId());
+        assertEquals("HIGH", cve.severity());
+        assertTrue(cve.fixedVersions().contains("4.0.4"));
+    }
 }

Reply via email to