fix(workflow): clone Input in subtemplate goroutine to prevent race condition#7134
fix(workflow): clone Input in subtemplate goroutine to prevent race condition#7134usernametooshort wants to merge 1 commit intoprojectdiscovery:devfrom
Conversation
The second goroutine in runWorkflowStep was not cloning ctx.Input before passing it to runWorkflowStep, unlike the first goroutine which properly calls ctx.Input.Clone(). The comment on both paths says 'clone the Input so that other parallel executions won't overwrite the shared variables' but only the first path was actually doing it. This causes a race condition where parallel subtemplate executions can corrupt each other's input data when modifying shared variables.
Neo - PR Security ReviewNo security issues found Highlights
Hardening Notes
Comment |
WalkthroughInput context cloning is added to two locations in workflow subtemplate execution to prevent shared-state mutations during parallel execution. Previously, subtemplates received a shared input reference; now each receives an isolated clone, eliminating potential race conditions. Changes
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~3 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
pkg/core/workflow_execute.go (2)
165-166: Update comment to reflect the cloned input.The comment says "create a new context with the same input" but the input is now cloned. Consider updating the comment to match the implementation and align with the similar comment at lines 138-139.
📝 Suggested comment update
go func(template *workflows.WorkflowTemplate) { - // create a new context with the same input but with unset callbacks + // create a new context with unset callbacks + // clone the Input so that other parallel executions won't overwrite the shared variables when subsequent templates are running subCtx := scan.NewScanContext(ctx.Context(), ctx.Input.Clone())🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/core/workflow_execute.go` around lines 165 - 166, The comment above the call to scan.NewScanContext(ctx.Context(), ctx.Input.Clone()) is inaccurate — it says "create a new context with the same input" but the code clones the input; update the comment to state that a new scan context is created with a cloned copy of the input (matching the implementation and the similar comment near lines 138-139) so readers understand the input is duplicated, not reused.
164-171: Consider usingdefer swg.Done()for consistency and safety.The other goroutine path (line 136) uses
defer swg.Done(), but this one callsswg.Done()directly at the end. Usingdeferensures the wait group is decremented even ifrunWorkflowSteppanics, preventing a potential deadlock.♻️ Suggested fix
go func(template *workflows.WorkflowTemplate) { + defer swg.Done() // create a new context with the same input but with unset callbacks subCtx := scan.NewScanContext(ctx.Context(), ctx.Input.Clone()) if err := e.runWorkflowStep(template, subCtx, results, swg, w); err != nil { gologger.Warning().Msgf(workflowStepExecutionError, template.Template, err) } - swg.Done() }(subtemplate)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/core/workflow_execute.go` around lines 164 - 171, The goroutine that invokes runWorkflowStep currently calls swg.Done() at the end, which can leak the wait group if runWorkflowStep panics; change the goroutine in which subtemplate is passed to call defer swg.Done() immediately after entering the goroutine (before calling runWorkflowStep) and remove the explicit swg.Done() at the end so the wait group is always decremented even on panic; locate the anonymous func where runWorkflowStep(template, subCtx, results, swg, w) is invoked and apply this change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@pkg/core/workflow_execute.go`:
- Around line 165-166: The comment above the call to
scan.NewScanContext(ctx.Context(), ctx.Input.Clone()) is inaccurate — it says
"create a new context with the same input" but the code clones the input; update
the comment to state that a new scan context is created with a cloned copy of
the input (matching the implementation and the similar comment near lines
138-139) so readers understand the input is duplicated, not reused.
- Around line 164-171: The goroutine that invokes runWorkflowStep currently
calls swg.Done() at the end, which can leak the wait group if runWorkflowStep
panics; change the goroutine in which subtemplate is passed to call defer
swg.Done() immediately after entering the goroutine (before calling
runWorkflowStep) and remove the explicit swg.Done() at the end so the wait group
is always decremented even on panic; locate the anonymous func where
runWorkflowStep(template, subCtx, results, swg, w) is invoked and apply this
change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b18aa235-182e-4355-b770-49d8312903f6
📒 Files selected for processing (1)
pkg/core/workflow_execute.go
dwisiswant0
left a comment
There was a problem hiding this comment.
Please file an issue before submitting fix patches.
Include reproduction steps as per the template and the exact nuclei command (or custom runner PoC for Nuclei SDK) that triggers unexpected behavior. The reproduction must be based on a realistic execution path that is fully concrete and reproducible.
Thanks!
Summary
Fixes a race condition in
runWorkflowStepwhere the second goroutine path does not clonectx.Inputbefore spawning parallel subtemplates.Problem
In
pkg/core/workflow_execute.go, there are two goroutine paths that run subtemplates:ctx.Input.Clone()(correct)ctx.Input(missing clone!)Both paths have the same comment: "clone the Input so that other parallel executions won't overwrite the shared variables" but only the first path actually clones.
Impact
When workflows execute multiple subtemplates in parallel via the second path, they share the same
ctx.Inputobject. This causes:Fix
Add
.Clone()call to match the first goroutine path, ensuring each subtemplate gets its own copy of the input data.Summary by CodeRabbit
Bug Fixes