Skip to content

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

Merged
lholmquist merged 1 commit into
orchestrator-1.9from
orchestrator-1.9-lholmquist-temp
Apr 9, 2026
Merged

fix(orchestrator): Address CVE-2026-3118 (#2597)#2736
lholmquist merged 1 commit into
orchestrator-1.9from
orchestrator-1.9-lholmquist-temp

Conversation

@lholmquist

Copy link
Copy Markdown
Member

cherry pick of PR #2597

  • 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 GraphQL query variables for filters and pagination

🐞 Bug fix ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Implement GraphQL query variables for filters, pagination, and queries to address CVE-2026-3118
• Update @urql/core dependency from ^4.1.4 to ^6.0.1
• Refactor filter builder to return FilterClause objects containing clause strings and variable
  metadata
• Refactor query builder to use parameterized queries with variable substitution instead of string
  interpolation
• Update all GraphQL queries to use gql template literals with named variables
Diagram
flowchart LR
  A["Filter/Query Builders"] -->|"Generate FilterClause<br/>with variables"| B["FilterClause Object"]
  B -->|"Contains clause string<br/>and variable metadata"| C["Query Builder"]
  C -->|"Constructs parameterized<br/>GraphQL query"| D["GraphQL Query"]
  D -->|"Passes variables<br/>separately"| E["URQL Client"]
  E -->|"Executes safely"| F["Data Index Service"]
Loading

Grey Divider

File Changes

1. workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts Enhancement, security +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 builder tests for variable-based approach

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


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

Refactor query builder to use parameterized queries

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 variable substitution

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


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

Update service to use parameterized GraphQL queries

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 variable-based queries

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


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

Add new 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 for query parameters

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


9. workspaces/orchestrator/plugins/orchestrator-backend/package.json Dependencies, security +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

Add changeset for CVE-2026-3118 fix

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


Grey Divider

Qodo Logo

@rhdh-qodo-merge

rhdh-qodo-merge Bot commented Apr 9, 2026

Copy link
Copy Markdown

Code Review by Qodo

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

Grey Divider


Action required

1. Enum variable typed String 🐞
Description
handleBinaryOperator declares single-value enum filter variables as type "String" while declaring
the same enum field as "[ProcessInstanceState!]" for array values, so one of those queries must be
invalid against the fixed server schema type. This can cause runtime GraphQL validation errors when
applying filters on the enum field.
Code

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

+  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';
+  }
Evidence
filterBuilder hardcodes enum array variables to [ProcessInstanceState!] but forces all single
values to String, and queryBuilder uses clauseVariableType verbatim in the operation signature;
therefore the generated query's variable type for the same field differs based on whether the filter
value is an array or not.

workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[183-229]
workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.ts[20-56]

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

### Issue description
`handleBinaryOperator` assigns `clauseVariableType = 'String'` for all single-value filters, even when `isEnumFilter(...)` is true. In the array branch it uses `[ProcessInstanceState!]`, meaning the same enum field will produce different GraphQL variable types depending on value cardinality, and `queryBuilder` will emit those types directly into the operation signature.

### Issue Context
GraphQL input field types are fixed in the schema; they cannot be both `String` and `ProcessInstanceState` depending on operator/value shape. With the current code, at least one of the enum filter modes will fail schema validation.

### Fix Focus Areas
- workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[183-212]
- workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.ts[20-36]

### What to change
- When `isEnumFilter(binaryFilter.field, type)` is true, set the single-value `paramType` to the correct enum type (e.g., `ProcessInstanceState` or `ProcessInstanceState!`) instead of `String`.
- Keep array and single-value enum typing consistent (e.g., `ProcessInstanceState` vs `[ProcessInstanceState!]`).
- If you don’t want to hardcode enum type names, consider deriving the correct variable type from schema/introspection and mapping it to the appropriate GraphQL type string.

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


2. Empty FilterClause breaks queries 🐞
Description
buildFilterCondition/handleLogicalFilter return {} cast as FilterClause, leaving clause and
clauseVariable undefined; downstream code treats the object as truthy and interpolates undefined
into the where clause. This can produce malformed GraphQL queries (e.g., {undefined} conditions)
and/or crash when iterating clauseVariable.
Code

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

+): FilterClause {
  if (!filters) {
-    return '';
+    return {} as FilterClause;
  }
Evidence
filterBuilder returns {} as a FilterClause, but FilterClause requires clause and
clauseVariable; DataIndexService checks if (filterCondition) (truthy for {}) and then uses
filterCondition?.clause inside query construction, which becomes undefined and is
string-interpolated into the final where clause.

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-266]

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 `{}` cast to `FilterClause`. This violates the `FilterClause` contract and leads to `undefined` being interpolated into `whereClause` and risks runtime errors when code assumes `clauseVariable` is an array.

### Issue Context
`DataIndexService.fetchInstances`/`fetchWorkflowInfos` treat any object returned by `buildFilterCondition` as truthy and append `{${filterCondition?.clause}}` into conditions. If `clause` is missing, the query string becomes invalid.

### Fix Focus Areas
- workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[76-92]
- workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[231-239]
- workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.ts[235-247]
- workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.ts[312-314]

### What to change
- Stop returning `{}` for “no filter”. Prefer one of:
 - Change the return type to `FilterClause | undefined` and return `undefined` for no-op cases, updating callers to check `filterCondition?.clause`.
 - Or always return a valid empty clause object: `{ clause: '', clauseVariable: [] }`.
- For `handleLogicalFilter`, since `LogicalFilter.operator` is required by the API type, consider throwing if it’s missing rather than returning an empty object.
- Ensure callers only append filter conditions when `filterCondition.clause` is non-empty.

ⓘ 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 9, 2026

Copy link
Copy Markdown

Comment on lines +195 to +212
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';
}

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. Enum variable typed string 🐞 Bug ≡ Correctness

handleBinaryOperator declares single-value enum filter variables as type "String" while declaring
the same enum field as "[ProcessInstanceState!]" for array values, so one of those queries must be
invalid against the fixed server schema type. This can cause runtime GraphQL validation errors when
applying filters on the enum field.
Agent Prompt
### Issue description
`handleBinaryOperator` assigns `clauseVariableType = 'String'` for all single-value filters, even when `isEnumFilter(...)` is true. In the array branch it uses `[ProcessInstanceState!]`, meaning the same enum field will produce different GraphQL variable types depending on value cardinality, and `queryBuilder` will emit those types directly into the operation signature.

### Issue Context
GraphQL input field types are fixed in the schema; they cannot be both `String` and `ProcessInstanceState` depending on operator/value shape. With the current code, at least one of the enum filter modes will fail schema validation.

### Fix Focus Areas
- workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[183-212]
- workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/queryBuilder.ts[20-36]

### What to change
- When `isEnumFilter(binaryFilter.field, type)` is true, set the single-value `paramType` to the correct enum type (e.g., `ProcessInstanceState` or `ProcessInstanceState!`) instead of `String`.
- Keep array and single-value enum typing consistent (e.g., `ProcessInstanceState` vs `[ProcessInstanceState!]`).
- If you don’t want to hardcode enum type names, consider deriving the correct variable type from schema/introspection and mapping it to the appropriate GraphQL type string.

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

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

2. Empty filterclause breaks queries 🐞 Bug ☼ Reliability

buildFilterCondition/handleLogicalFilter return {} cast as FilterClause, leaving clause and
clauseVariable undefined; downstream code treats the object as truthy and interpolates undefined
into the where clause. This can produce malformed GraphQL queries (e.g., {undefined} conditions)
and/or crash when iterating clauseVariable.
Agent Prompt
### Issue description
`buildFilterCondition` (and `handleLogicalFilter` when `operator` is missing) returns `{}` cast to `FilterClause`. This violates the `FilterClause` contract and leads to `undefined` being interpolated into `whereClause` and risks runtime errors when code assumes `clauseVariable` is an array.

### Issue Context
`DataIndexService.fetchInstances`/`fetchWorkflowInfos` treat any object returned by `buildFilterCondition` as truthy and append `{${filterCondition?.clause}}` into conditions. If `clause` is missing, the query string becomes invalid.

### Fix Focus Areas
- workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[76-92]
- workspaces/orchestrator/plugins/orchestrator-backend/src/helpers/filterBuilder.ts[231-239]
- workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.ts[235-247]
- workspaces/orchestrator/plugins/orchestrator-backend/src/service/DataIndexService.ts[312-314]

### What to change
- Stop returning `{}` for “no filter”. Prefer one of:
  - Change the return type to `FilterClause | undefined` and return `undefined` for no-op cases, updating callers to check `filterCondition?.clause`.
  - Or always return a valid empty clause object: `{ clause: '', clauseVariable: [] }`.
- For `handleLogicalFilter`, since `LogicalFilter.operator` is required by the API type, consider throwing if it’s missing rather than returning an empty object.
- Ensure callers only append filter conditions when `filterCondition.clause` is non-empty.

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

@lholmquist
lholmquist merged commit 189c9fe into orchestrator-1.9 Apr 9, 2026
9 checks passed
@lholmquist
lholmquist deleted the orchestrator-1.9-lholmquist-temp branch April 9, 2026 13:43
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