Skip to content

Merge dev to master#12

Closed
ragsav wants to merge 70 commits intomasterfrom
dev
Closed

Merge dev to master#12
ragsav wants to merge 70 commits intomasterfrom
dev

Conversation

@ragsav
Copy link
Copy Markdown
Contributor

@ragsav ragsav commented Feb 5, 2026

No description provided.

const fields = useMemo(() => {
if (!workflowContext || !dataSource) return [];

const match = dataSource.match(/\{\{ctx\.([^}]+)\}\}/);

Check failure

Code scanning / CodeQL

Polynomial regular expression used on uncontrolled data High

This
regular expression
that depends on
library input
may run slow on strings starting with '{{ctx.' and with many repetitions of '{{ctx.|'.
if (!current[pathParts[i]]) current[pathParts[i]] = {};
current = current[pathParts[i]];
}
current[pathParts[pathParts.length - 1]] = newValue;

Check warning

Code scanning / CodeQL

Prototype-polluting function Medium

The property chain
here
is recursively assigned to
current
without guarding against prototype pollution.

Copilot Autofix

AI 18 days ago

In general, to fix unsafe deep assignment / merge functions you must prevent special prototype-related keys (__proto__, constructor, and often prototype) from being used as property names when creating or traversing nested objects. Alternatively, you can restrict recursive merging to properties that already exist as own properties on the destination object. This prevents attackers from reaching and modifying Object.prototype through crafted paths.

For this specific handleSpecChange function in packages/widgets-ui/src/vega/chartBuilder.jsx, the minimal and safest fix is to introduce a small guard that checks each path segment before it is used to access or create properties on current. If any segment is __proto__, constructor, or prototype, we should abort the update and return the previous state unchanged. This preserves existing functionality for all legitimate keys while eliminating the possibility of prototype pollution.

Concretely:

  • Inside handleSpecChange, after computing const pathParts = updatePath.split('.'), introduce a helper isUnsafeKey function (inside handleSpecChange to keep scope local) that returns true for __proto__, constructor, or prototype.
  • When iterating over pathParts in the for loop (lines 69–72), before using pathParts[i] to index into current, check if (isUnsafeKey(pathParts[i])) return prev;.
  • Before the final assignment on line 73, check if (isUnsafeKey(lastKey)) return prev;.
  • No external dependencies or imports are needed; this is pure JS.

This approach changes only the behavior for unsafe keys and does not affect existing valid usage of handleSpecChange.

Suggested changeset 1
packages/widgets-ui/src/vega/chartBuilder.jsx

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/widgets-ui/src/vega/chartBuilder.jsx b/packages/widgets-ui/src/vega/chartBuilder.jsx
--- a/packages/widgets-ui/src/vega/chartBuilder.jsx
+++ b/packages/widgets-ui/src/vega/chartBuilder.jsx
@@ -63,14 +63,28 @@
       // Deep clone and update
       const nextSpec = JSON.parse(JSON.stringify(prev));
       
+      // Helper to prevent prototype pollution via special keys
+      const isUnsafeKey = (key) =>
+        key === '__proto__' || key === 'constructor' || key === 'prototype';
+      
       // Navigate to the target path and apply update
       const pathParts = updatePath.split('.');
       let current = nextSpec;
       for (let i = 0; i < pathParts.length - 1; i++) {
-        if (!current[pathParts[i]]) current[pathParts[i]] = {};
-        current = current[pathParts[i]];
+        const segment = pathParts[i];
+        if (isUnsafeKey(segment)) {
+          // Abort update if an unsafe key is encountered
+          return prev;
+        }
+        if (!current[segment]) current[segment] = {};
+        current = current[segment];
       }
-      current[pathParts[pathParts.length - 1]] = newValue;
+      const lastKey = pathParts[pathParts.length - 1];
+      if (isUnsafeKey(lastKey)) {
+        // Abort update if an unsafe key is used for the final assignment
+        return prev;
+      }
+      current[lastKey] = newValue;
       
       return nextSpec;
     });
EOF
@@ -63,14 +63,28 @@
// Deep clone and update
const nextSpec = JSON.parse(JSON.stringify(prev));

// Helper to prevent prototype pollution via special keys
const isUnsafeKey = (key) =>
key === '__proto__' || key === 'constructor' || key === 'prototype';

// Navigate to the target path and apply update
const pathParts = updatePath.split('.');
let current = nextSpec;
for (let i = 0; i < pathParts.length - 1; i++) {
if (!current[pathParts[i]]) current[pathParts[i]] = {};
current = current[pathParts[i]];
const segment = pathParts[i];
if (isUnsafeKey(segment)) {
// Abort update if an unsafe key is encountered
return prev;
}
if (!current[segment]) current[segment] = {};
current = current[segment];
}
current[pathParts[pathParts.length - 1]] = newValue;
const lastKey = pathParts[pathParts.length - 1];
if (isUnsafeKey(lastKey)) {
// Abort update if an unsafe key is used for the final assignment
return prev;
}
current[lastKey] = newValue;

return nextSpec;
});
Copilot is powered by AI and may make mistakes. Always verify output.
Unable to commit as this autofix suggestion is now outdated
@ragsav ragsav closed this Mar 27, 2026
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.

3 participants