Skip to content

fix(orchestrator): Address CVE-2026-3118 (#2597) (#2727)#2730

Merged
lholmquist merged 1 commit into
workspace/orchestratorfrom
lholmquist-orchestrator-patch-1.8-cve
Apr 8, 2026
Merged

fix(orchestrator): Address CVE-2026-3118 (#2597) (#2727)#2730
lholmquist merged 1 commit into
workspace/orchestratorfrom
lholmquist-orchestrator-patch-1.8-cve

Conversation

@lholmquist

Copy link
Copy Markdown
Member
  • fix: Update grapql client

  • Filters, pagination and queries now use query variables

fixes CVE-2026-3118 and relates to JIRA https://redhat.atlassian.net/browse/RHIDP-12388 and https://redhat.atlassian.net/browse/RHIDP-12583

Hey, I just made a Pull Request!

✔️ Checklist

  • A changeset describing the change and affected packages. (more info)
  • Added or Updated documentation
  • Tests for new functionality and regression tests for bug fixes
  • Screenshots attached (for UI changes)

* fix: Update grapql client

* Filters, pagination and queries now use query variables

fixes CVE-2026-3118 and relates to JIRA https://redhat.atlassian.net/browse/RHIDP-12388 and https://redhat.atlassian.net/browse/RHIDP-12583
@rhdh-qodo-merge

Copy link
Copy Markdown

Review Summary by Qodo

Fix CVE-2026-3118 by implementing parameterized GraphQL queries with variables

🐞 Bug fix ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Migrate GraphQL queries to use query variables instead of string interpolation
• Update @urql/core dependency from 4.1.4 to 6.0.1 to address CVE-2026-3118
• Refactor filter builder to return FilterClause objects with separated clause and variables
• Implement parameterized queries for filters, pagination, and orderBy operations
• Update test cases to validate variable substitution and formatted values
Diagram
flowchart LR
  A["String Interpolation<br/>GraphQL Queries"] -->|"Refactor to use<br/>Query Variables"| B["Parameterized<br/>GraphQL Queries"]
  C["Filter Builder<br/>Returns String"] -->|"Return FilterClause<br/>with Variables"| D["FilterClause Object<br/>clause + variables"]
  E["@urql/core 4.1.4<br/>CVE-2026-3118"] -->|"Update to 6.0.1"| F["@urql/core 6.0.1<br/>Secure"]
  D -->|"Pass to Query Builder"| B
  B -->|"Execute with<br/>Parameter Variables"| G["Secure GraphQL<br/>Execution"]
Loading

Grey Divider

File Changes

1. workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts ✨ Enhancement +105/-25

Refactor filter builder to use query variables

workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts


2. workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilders.test.ts 🧪 Tests +156/-46

Update filter tests for parameterized queries

workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilders.test.ts


3. workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.ts ✨ Enhancement +63/-25

Implement parameterized GraphQL query construction

workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.ts


View more (7)
4. workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.test.ts 🧪 Tests +7/-18

Update query builder tests for variables

workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.test.ts


5. workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.ts ✨ Enhancement +102/-22

Integrate parameterized queries in data service

workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.ts


6. workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.test.ts 🧪 Tests +197/-93

Update service tests for query variables

workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.test.ts


7. workspaces/orchestrator/plugins/orchestrator-backend/src/types/filterClause.ts ✨ Enhancement +26/-0

Define FilterClause and FilterClauseVariable types

workspaces/orchestrator/plugins/orchestrator-backend/src/types/filterClause.ts


8. workspaces/orchestrator/plugins/orchestrator-backend/src/types/pagination.ts ✨ Enhancement +7/-1

Add PaginationQueryVariable type definition

workspaces/orchestrator/plugins/orchestrator-backend/src/types/pagination.ts


9. workspaces/orchestrator/plugins/orchestrator-backend/package.json Dependencies +1/-1

Update @urql/core dependency to 6.0.1

workspaces/orchestrator/plugins/orchestrator-backend/package.json


10. workspaces/orchestrator/.changeset/five-meals-cover.md 📝 Documentation +6/-0

Document CVE fix and query variable refactoring

workspaces/orchestrator/.changeset/five-meals-cover.md


Grey Divider

Qodo Logo

@rhdh-qodo-merge

rhdh-qodo-merge Bot commented Apr 8, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2)   📘 Rule violations (0)   📎 Requirement gaps (0)   🎨 UX Issues (0)
🐞\ ≡ Correctness (2)

Grey Divider


Action required

1. Empty FilterClause is truthy 🐞
Description
buildFilterCondition returns {} cast as FilterClause when filters is missing, producing a
truthy object with undefined clause/clauseVariable. Callers like DataIndexService treat this as
present and can build GraphQL where strings containing {undefined} and/or pass malformed filter
variables downstream.
Code

workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[R236-239]

+): FilterClause {
  if (!filters) {
-    return '';
+    return {} as FilterClause;
  }
Evidence
The refactor changed empty-filter behavior from a falsy string ('') to a truthy object (`{} as
FilterClause). DataIndexService checks if (filterCondition)` and interpolates
filterCondition?.clause into the whereClause; if clause is undefined, the resulting query
contains the literal string undefined inside the where expression, which will be rejected by the
GraphQL server. Additionally, the query builder expects clauseVariable entries to be well-formed
when generating the query header.

workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[231-247]
workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[76-92]
workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.ts[279-323]
workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.ts[20-41]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`buildFilterCondition()` (and `handleLogicalFilter()` when `operator` is missing) returns `{} as FilterClause`. This creates a truthy value with missing fields, which then gets treated as a real filter and can render `where` fragments like `{undefined}`.

### Issue Context
Callers (e.g., `DataIndexService`) use `if (filterCondition)` to decide whether to include the filter, and then interpolate `filterCondition.clause`.

### Fix approach
Prefer one of these (choose consistently across the codebase):
1) Change return type to `FilterClause | undefined` and return `undefined` for “no filter / invalid filter”, OR
2) Return a structurally valid empty clause: `{ clause: '', clauseVariable: [] }` and update call sites to check `filterCondition.clause` (non-empty) rather than object truthiness.

### Fix Focus Areas
- workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[76-92]
- workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[231-247]
- workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.ts[222-277]
- workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.ts[279-323]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Enum variable type mismatch 🐞
Description
handleBinaryOperator sets the GraphQL variable type for scalar enum filters (e.g. state EQ ...) to
String while using [ProcessInstanceState!] for array enum filters. This inconsistency can cause
GraphQL validation errors if the schema expects ProcessInstanceState for equal on state.
Code

workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[R195-216]

+  let formattedValue: any;
+  let paramType: string;
+  if (Array.isArray(binaryFilter.value)) {
+    formattedValue = binaryFilter.value.map(v =>
+      formatValue(binaryFilter.field, v, fieldDef, type),
+    );
+    paramType = isEnumFilter(binaryFilter.field, type)
+      ? '[ProcessInstanceState!]'
+      : '[String!]';
+  } else {
+    formattedValue = formatValue(
+      binaryFilter.field,
+      binaryFilter.value,
+      fieldDef,
+      type,
+    );
+    paramType = 'String';
+  }
+
+  const clauseVariableName = `clauseVariable${nonSecureRandomAlphaNumeric()}`;
+  const clause = `${binaryFilter.field}: {${getGraphQLOperator(binaryFilter.operator)}: $${clauseVariableName}}`;
+  const filterClauseVariable: FilterClauseVariable = {
Evidence
The code explicitly treats ProcessInstance.state as an enum (isEnumFilter returns true for
state). In the array case it declares the variable as [ProcessInstanceState!], but in the scalar
case it always declares String. If the equal input type is ProcessInstanceState (as implied by
the chosen list type), GraphQL will reject using a $var: String in a position requiring
ProcessInstanceState.

workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[164-174]
workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[183-229]
workspaces/orchestrator/plugins/orchestrator-common/src/models.ts[19-26]
workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.ts[20-36]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Enum filters for `state` use inconsistent GraphQL variable types: array values use `[ProcessInstanceState!]` but scalar values use `String`. This can break queries depending on the GraphQL schema.

### Issue Context
`isEnumFilter()` identifies `state` as enum-like, and the code already hardcodes `ProcessInstanceState` for the list case.

### Fix approach
Update the scalar branch in `handleBinaryOperator()` so that when `isEnumFilter(binaryFilter.field, type)` is true, `paramType` is the matching enum type (e.g., `ProcessInstanceState`), not `String`.

Optionally (more robust): derive the correct GraphQL input type name from introspection rather than hardcoding `ProcessInstanceState`.

### Fix Focus Areas
- workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[164-229]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@sonarqubecloud

sonarqubecloud Bot commented Apr 8, 2026

Copy link
Copy Markdown

Comment on lines +236 to 239
): FilterClause {
if (!filters) {
return '';
return {} as FilterClause;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Empty filterclause is truthy 🐞 Bug ≡ Correctness

buildFilterCondition returns {} cast as FilterClause when filters is missing, producing a
truthy object with undefined clause/clauseVariable. Callers like DataIndexService treat this as
present and can build GraphQL where strings containing {undefined} and/or pass malformed filter
variables downstream.
Agent Prompt
### Issue description
`buildFilterCondition()` (and `handleLogicalFilter()` when `operator` is missing) returns `{} as FilterClause`. This creates a truthy value with missing fields, which then gets treated as a real filter and can render `where` fragments like `{undefined}`.

### Issue Context
Callers (e.g., `DataIndexService`) use `if (filterCondition)` to decide whether to include the filter, and then interpolate `filterCondition.clause`.

### Fix approach
Prefer one of these (choose consistently across the codebase):
1) Change return type to `FilterClause | undefined` and return `undefined` for “no filter / invalid filter”, OR
2) Return a structurally valid empty clause: `{ clause: '', clauseVariable: [] }` and update call sites to check `filterCondition.clause` (non-empty) rather than object truthiness.

### Fix Focus Areas
- workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[76-92]
- workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[231-247]
- workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.ts[222-277]
- workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.ts[279-323]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +195 to +216
let formattedValue: any;
let paramType: string;
if (Array.isArray(binaryFilter.value)) {
formattedValue = binaryFilter.value.map(v =>
formatValue(binaryFilter.field, v, fieldDef, type),
);
paramType = isEnumFilter(binaryFilter.field, type)
? '[ProcessInstanceState!]'
: '[String!]';
} else {
formattedValue = formatValue(
binaryFilter.field,
binaryFilter.value,
fieldDef,
type,
);
paramType = 'String';
}

const clauseVariableName = `clauseVariable${nonSecureRandomAlphaNumeric()}`;
const clause = `${binaryFilter.field}: {${getGraphQLOperator(binaryFilter.operator)}: $${clauseVariableName}}`;
const filterClauseVariable: FilterClauseVariable = {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Enum variable type mismatch 🐞 Bug ≡ Correctness

handleBinaryOperator sets the GraphQL variable type for scalar enum filters (e.g. state EQ ...) to
String while using [ProcessInstanceState!] for array enum filters. This inconsistency can cause
GraphQL validation errors if the schema expects ProcessInstanceState for equal on state.
Agent Prompt
### Issue description
Enum filters for `state` use inconsistent GraphQL variable types: array values use `[ProcessInstanceState!]` but scalar values use `String`. This can break queries depending on the GraphQL schema.

### Issue Context
`isEnumFilter()` identifies `state` as enum-like, and the code already hardcodes `ProcessInstanceState` for the list case.

### Fix approach
Update the scalar branch in `handleBinaryOperator()` so that when `isEnumFilter(binaryFilter.field, type)` is true, `paramType` is the matching enum type (e.g., `ProcessInstanceState`), not `String`.

Optionally (more robust): derive the correct GraphQL input type name from introspection rather than hardcoding `ProcessInstanceState`.

### Fix Focus Areas
- workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[164-229]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@lholmquist lholmquist merged commit 480bde1 into workspace/orchestrator Apr 8, 2026
9 checks passed
@lholmquist lholmquist deleted the lholmquist-orchestrator-patch-1.8-cve branch June 3, 2026 19:23
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