Skip to content

fix(crd-generator): honor multi-package exclusions - #7952

Open
GrosQuildu wants to merge 2 commits into
fabric8io:mainfrom
GrosQuildu:ptp-67-crd-exclude-packages
Open

fix(crd-generator): honor multi-package exclusions#7952
GrosQuildu wants to merge 2 commits into
fabric8io:mainfrom
GrosQuildu:ptp-67-crd-exclude-packages

Conversation

@GrosQuildu

@GrosQuildu GrosQuildu commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Description

The CRD generator's CustomResourceCollector.withExcludePackages method does not correctly combine multiple excluded package prefixes. It creates one predicate per package as !className.startsWith(pkg), then combines those negated predicates with or. As a result, a class under one excluded package is retained as long as it does not also start with another excluded package.

This bypass affects the collector used by the CRD generator Maven plugin and CLI. A build that scans project classes or dependencies and configures multiple package exclusions can still load and generate CRDs for a class under an excluded prefix. The v2 CRD generator later derives CustomResourceInfo from the retained class and invokes the custom resource default constructor, so the exclusion bypass can execute code and emit CRDs that the build configuration intended to suppress.

The vulnerable predicate composition is equivalent to:

!className.startsWith("com.example") || !className.startsWith("com.other")

For com.example.Test, the first condition is false but the second condition is true, so the excluded class is retained.

Exploit Scenario

An attacker contributes or compromises a dependency that is included in a downstream project's CRD generation classpath. The downstream project configures the generator to scan dependencies but excludes the attacker's package along with at least one other package. During the build, the collector's OR-composed exclude predicates retain the attacker's custom resource class. The generator loads the class, constructs generator metadata from it, invokes its default constructor, and emits CRD output for a resource that the exclusion was meant to block.

The following regression test exercises the project code path directly:

  @Test
  void givenClassNameAndMultipleExcludePackages_thenNoLoading() {
    customResourceCollector.withCustomResourceClass("com.example.Test");
    customResourceCollector.withExcludePackages(Arrays.asList("com.example", "com.other"));

    List<Class<? extends HasMetadata>> classes = customResourceCollector.findCustomResourceClasses();
    verify(customResourceClassLoader, times(0)).loadCustomResourceClass(anyString());
    assertEquals(0, classes.size());
  }

Run the regression test with:

./mvnw -B -ntp -pl crd-generator/collector -am -DskipITs \
  -Dsurefire.failIfNoSpecifiedTests=false \
  -Dtest=CustomResourceCollectorTest#givenClassNameAndMultipleExcludePackages_thenNoLoading \
  test

Before the patch, the test fails because the excluded class is loaded:

Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
customResourceClassLoader.loadCustomResourceClass(<any string>) was invoked with com.example.Test.

After the patch, the same command succeeds:

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS

Threat Model

This seems to be just a technical bug.

Fix

Combine the negated exclusion predicates with and, so a retained class must avoid every excluded prefix.


Paweł Płatek from Trail of Bits in collaboration with OpenAI.

@GrosQuildu
GrosQuildu marked this pull request as ready for review June 26, 2026 14:09
GrosQuildu added a commit to GrosQuildu/kubernetes-client that referenced this pull request Jun 26, 2026
@GrosQuildu
GrosQuildu force-pushed the ptp-67-crd-exclude-packages branch from 04eabaf to 8dc59ef Compare June 26, 2026 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant