Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Forms
DescriptionUse after free in Forms
ComponentForms
Bug ClassUAF
Tracker523748081
Fix commit126b63885ce7 (chromium/src) +360/-58
CISA KEVNot listed
CreditedGoogle
Disclosed2026-07-08

Changed Functions

FunctionChangeNotes
if
third_party/blink/renderer/core/html/forms/html_field_set_element.cc
modified

Files Changed

  • third_party/blink/renderer/core/html/custom/custom_element_definition.cc
  • third_party/blink/renderer/core/html/forms/file_input_type.cc
  • third_party/blink/renderer/core/html/forms/file_input_type.h
  • third_party/blink/renderer/core/html/forms/html_field_set_element.cc
  • third_party/blink/renderer/core/html/forms/html_field_set_element.h
  • third_party/blink/renderer/core/html/forms/html_form_control_element.cc
From 126b63885ce76abb52318ff90cb0534339820326 Mon Sep 17 00:00:00 2001
From: Joey Arhar <jarhar@chromium.org>
Date: Thu, 25 Jun 2026 08:05:47 -0700
Subject: [PATCH] Don't fire change event during mutations affecting disabledness

Running script inside mutations (InsertedInto, RemovedFrom, MovedFrom)
is not allowed.

Fixed: 523756329, 523748081, 523737685
Change-Id: Ib0842d5c8fcf837d96f270a8d50d4189ef151d06
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7948021
Reviewed-by: Joey Arhar <jarhar@chromium.org>
Reviewed-by: David Baron <dbaron@chromium.org>
Commit-Queue: Joey Arhar <jarhar@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1652428}
---

diff --git a/third_party/blink/renderer/core/html/custom/custom_element_definition.cc b/third_party/blink/renderer/core/html/custom/custom_element_definition.cc
index 68afcd48..d0d4b43c 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_definition.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_element_definition.cc
@@ -248,8 +248,10 @@
   if (ListedElement* listed_element = ListedElement::From(element)) {
     if (element.FastHasAttribute(html_names::kReadonlyAttr))
       listed_element->ReadonlyAttributeChanged();
-    if (element.FastHasAttribute(html_names::kDisabledAttr))
-      listed_element->DisabledAttributeChanged();
+    if (element.FastHasAttribute(html_names::kDisabledAttr)) {
+      listed_element->DisabledAttributeChanged(
+          DisabledChangedReason::kAttributeChanged);
+    }
   }
 
   if (IsFormAssociated())
diff --git a/third_party/blink/renderer/core/html/forms/file_input_type.cc b/third_party/blink/renderer/core/html/forms/file_input_type.cc
index 8382530..2240228 100644
--- a/third_party/blink/renderer/core/html/forms/file_input_type.cc
+++ b/third_party/blink/renderer/core/html/forms/file_input_type.cc
@@ -418,7 +418,7 @@
   return GetElement().EnsureShadowSubtree()->lastChild();
 }
 
-void FileInputType::DisabledAttributeChanged() {
+void FileInputType::DisabledAttributeChanged(DisabledChangedReason reason) {
   if (Element* button = UploadButton()) {
     button->SetBooleanAttribute(html_names::kDisabledAttr,
                                 GetElement().IsDisabledFormControl());
diff --git a/third_party/blink/renderer/core/html/forms/file_input_type.h b/third_party/blink/renderer/core/html/forms/file_input_type.h
index d0be314..152b29c 100644
--- a/third_party/blink/renderer/core/html/forms/file_input_type.h
+++ b/third_party/blink/renderer/core/html/forms/file_input_type.h
@@ -88,7 +88,7 @@
   String DroppedFileSystemId() override;
   void CreateShadowSubtree() override;
   HTMLInputElement* UploadButton() const override;
-  void DisabledAttributeChanged() override;
+  void DisabledAttributeChanged(DisabledChangedReason) override;
   void MultipleAttributeChanged() override;
   String DefaultToolTip(const InputTypeView&) const override;
   void CopyNonAttributeProperties(const HTMLInputElement&) override;
diff --git a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
index bca3141..5e947482 100644
--- a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
@@ -24,6 +24,7 @@
 
 #include "third_party/blink/renderer/core/html/forms/html_field_set_element.h"
 
+#include "base/auto_reset.h"
 #include "third_party/blink/renderer/core/dom/element_traversal.h"
 #include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
 #include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
@@ -35,6 +36,7 @@
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/core/layout/forms/layout_fieldset.h"
 #include "third_party/blink/renderer/core/layout/layout_block.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 
 namespace blink {
@@ -124,18 +126,21 @@
 // Returns a disabled focused element if it's in descendants of |base|.
 Element*
 HTMLFieldSetElement::InvalidateDescendantDisabledStateAndFindFocusedOne(
-    Element& base) {
+    Element& base,
+    DisabledChangedReason reason) {
   Element* focused_element = AdjustedFocusedElementInTreeScope();
   bool should_blur = false;
   {
     EventDispatchForbiddenScope event_forbidden;
     for (HTMLElement& element : Traversal<HTMLElement>::DescendantsOf(base)) {
-      if (auto* control = DynamicTo<HTMLFormControlElement>(element))
-        control->AncestorDisabledStateWasChanged();
-      else if (element.IsFormAssociatedCustomElement())
-        element.EnsureElementInternals().AncestorDisabledStateWasChanged();
-      else
+      if (auto* control = DynamicTo<HTMLFormControlElement>(element)) {
+        control->AncestorDisabledStateWasChanged(reason);
+      } else if (element.IsFormAssociatedCustomElement()) {
+        element.EnsureElementInternals().AncestorDisabledStateWasChanged(
+            reason);
+      } else {
         continue;
+      }
       if (focused_element == &element && element.IsDisabledFormControl())
         should_blur = true;
     }
@@ -143,11 +148,12 @@
   return should_blur ? focused_element : nullptr;
 }
 
-void HTMLFieldSetElement::DisabledAttributeChanged() {
+void HTMLFieldSetElement::DisabledAttributeChanged(
+    DisabledChangedReason reason) {
   bool was_disabled = IsSelfDisabledIgnoringAncestors();
   // This element must be updated before the style of nodes in its subtree gets
   // recalculated.
-  HTMLFormControlElement::DisabledAttributeChanged();
+  HTMLFormControlElement::DisabledAttributeChanged(reason);
   if (was_disabled != IsSelfDisabledIgnoringAncestors()) {
     Document& document = GetDocument();
     if (was_disabled) {
@@ -157,16 +163,18 @@
     }
   }
   if (Element* focused_element =
-          InvalidateDescendantDisabledStateAndFindFocusedOne(*this))
+          InvalidateDescendantDisabledStateAndFindFocusedOne(*this, reason)) {
     focused_element->blur();
+  }
 }
 
-void HTMLFieldSetElement::AncestorDisabledStateWasChanged() {
+void HTMLFieldSetElement::AncestorDisabledStateWasChanged(
+    DisabledChangedReason reason) {
   ancestor_disabled_state_ = AncestorDisabledState::kUnknown;
   // Do not re-enter HTMLFieldSetElement::DisabledAttributeChanged(), so that
   // we only invalidate this element's own disabled state and do not traverse
   // the descendants.
-  HTMLFormControlElement::DisabledAttributeChanged();
+  HTMLFormControlElement::DisabledAttributeChanged(reason);
 }
 
 void HTMLFieldSetElement::DidMoveToNewDocument(Document& old_document) {
@@ -184,9 +192,10 @@
     EventDispatchForbiddenScope event_forbidden;
     for (HTMLLegendElement& legend :
          Traversal<HTMLLegendElement>::ChildrenOf(*this)) {
-      if (Element* element =
-              InvalidateDescendantDisabledStateAndFindFocusedOne(legend))
+      if (Element* element = InvalidateDescendantDisabledStateAndFindFocusedOne(
+              legend, DisabledChangedReason::kFieldsetChildrenChanged)) {
         focused_element = element;
+      }
     }
   }
   if (!GetDocument().StatePreservingAtomicMoveInProgress() && focused_element) {
diff --git a/third_party/blink/renderer/core/html/forms/html_field_set_element.h b/third_party/blink/renderer/core/html/forms/html_field_set_element.h
index 69c6ded..1c132ab 100644
--- a/third_party/blink/renderer/core/html/forms/html_field_set_element.h
+++ b/third_party/blink/renderer/core/html/forms/html_field_set_element.h
@@ -49,8 +49,8 @@
   void UpdateMenuItemCheckableExclusivity(HTMLMenuItemElement*);
 
  protected:
-  void DisabledAttributeChanged() override;
-  void AncestorDisabledStateWasChanged() override;
+  void DisabledAttributeChanged(DisabledChangedReason) override;
+  void AncestorDisabledStateWasChanged(DisabledChangedReason) override;
   void DidMoveToNewDocument(Document& old_document) override;
 
  private:
@@ -70,7 +70,9 @@
   bool MatchesEnabledPseudoClass() const final;
   bool MatchesDisabledPseudoClass() const final;
 
-  Element* InvalidateDescendantDisabledStateAndFindFocusedOne(Element& base);
+  Element* InvalidateDescendantDisabledStateAndFindFocusedOne(
+      Element& base,
+      DisabledChangedReason);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/html_form_control_element.cc b/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
index a60b067..e6bedb46 100644
--- a/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
@@ -149,7 +149,7 @@
   HTMLElement::AttributeChanged(params);
   if (params.name == html_names::kDisabledAttr &&
       params.old_value.IsNull() != params.new_value.IsNull()) {
-    DisabledAttributeChanged();
+    DisabledAttributeChanged(DisabledChangedReason::kAttributeChanged);
     if (params.reason == AttributeModificationReason::kDirectly &&
         IsDisabledFormControl() && AdjustedFocusedElementInTreeScope() == this)
       blur();
@@ -181,12 +181,13 @@
   }
 }
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/insertBefore-iframe-crash.html b/third_party/blink/web_tests/external/wpt/dom/nodes/insertBefore-iframe-crash.html
new file mode 100644
index 0000000..0effea6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/insertBefore-iframe-crash.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html class="test-wait">
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://issues.chromium.org/issues/523756329">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<style>
+  #num {
+    width: 200px;
+    height: 60px;
+    font-size: 30px;
+  }
+</style>
+
+<fieldset id=fs disabled>
+  <legend id=legend1>
+    <input id=num type=number value=5>
+  </legend>
+  <legend id=legend2>second</legend>
+</fieldset>
+
+<div id=iframe-host>
+  <iframe id=iframe src="about:blank"></iframe>
+</div>
+
+<script>
+window.onload = async () => {
+  const fs = document.getElementById('fs');
+  const legend1 = document.getElementById('legend1');
+  const legend2 = document.getElementById('legend2');
+  const num = document.getElementById('num');
+  const iframe = document.getElementById('iframe');
+
+  await new Promise(requestAnimationFrame);
+  await new Promise(requestAnimationFrame);
+
+  num.addEventListener('change', () => {
+    iframe.remove();
+  });
+
+  // Target the spin button (step-up arrow) which is on the right edge, upper half.
+  // We calculate the offset from the center of the input element.
+  const rect = num.getBoundingClientRect();
+  const offsetX = Math.round(rect.width / 2 - 7);
+  const offsetY = Math.round(-rect.height / 4);
+
+  // Press and hold the spin button
+  await new test_driver.Actions()
+    .pointerMove(offsetX, offsetY, {origin: num})
+    .pointerDown()
+    .send();
+
+  // Wait a frame to ensure the pointer down is processed and value is stepped
+  await new Promise(requestAnimationFrame);
+
+  fs.insertBefore(legend2, legend1);
+  document.body.appendChild(iframe);
+  document.documentElement.classList.remove('test-wait');
+}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/moveBefore-iframe-crash.html b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/moveBefore-iframe-crash.html
new file mode 100644
index 0000000..acc8fca
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/moveBefore-iframe-crash.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html class="test-wait">
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://issues.chromium.org/issues/523756329">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<style>
+  #num {
+    width: 200px;
+    height: 60px;
+    font-size: 30px;
+  }
+</style>
+
+<fieldset id=fs disabled>
+  <legend id=legend1>
+    <input id=num type=number value=5>
+  </legend>
+  <legend id=legend2>second</legend>
+</fieldset>
+
+<div id=iframe-host>
+  <iframe id=iframe src="about:blank"></iframe>
+</div>
+
+<script>
+window.onload = async () => {
+  const fs = document.getElementById('fs');
+  const legend1 = document.getElementById('legend1');
+  const legend2 = document.getElementById('legend2');
+  const num = document.getElementById('num');
+  const iframe = document.getElementById('iframe');
+
+  await new Promise(requestAnimationFrame);
+  await new Promise(requestAnimationFrame);
+
+  num.addEventListener('change', () => {
+    iframe.remove();
+  });
+
+  // Target the spin button (step-up arrow) which is on the right edge, upper half.
+  // We calculate the offset from the center of the input element.
+  const rect = num.getBoundingClientRect();
+  const offsetX = Math.round(rect.width / 2 - 7);
+  const offsetY = Math.round(-rect.height / 4);
+
+  // Press and hold the spin button
+  await new test_driver.Actions()
+    .pointerMove(offsetX, offsetY, {origin: num})
+    .pointerDown()
+    .send();
+
+  // Wait a frame to ensure the pointer down is processed and value is stepped
+  await new Promise(requestAnimationFrame);
+
+  fs.moveBefore(legend2, legend1);
+  document.body.appendChild(iframe);
+  document.documentElement.classList.remove('test-wait');
+}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/moveBefore-legend-input-crash.html b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/moveBefore-legend-input-crash.html
new file mode 100644
index 0000000..06b55c2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/moveBefore-legend-input-crash.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html class="test-wait">
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://issues.chromium.org/issues/523756329">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<style>
+  #num {
+    width: 200px;
+    height: 60px;
+    font-size: 30px;
+  }
+</style>
+
+<fieldset id=fieldset disabled>
+  <legend id=legend>
+    <input id=num type=number value=5>
+  </legend>
+  <span id=pad></span>
+</fieldset>
+
+<div id=iframe-host>
+  <iframe id=iframe srcdoc="<h1>iframe</h1>"></iframe>
+</div>
+
+<script>
+window.onload = async () => {
+  const fieldset = document.getElementById('fieldset');
+  const legend = document.getElementById('legend');
+  const num = document.getElementById('num');
+  const iframe = document.getElementById('iframe');
+
+  await new Promise(requestAnimationFrame);
+  await new Promise(requestAnimationFrame);
+
+  num.addEventListener('change', () => {
+    iframe.remove();
+  });
+
+  // Target the spin button (step-up arrow) which is on the right edge, upper half.
+  const rect = num.getBoundingClientRect();
+  const offsetX = Math.round(rect.width / 2 - 7);
+  const offsetY = Math.round(-rect.height / 4);
+
+  // Press and hold the spin button to get capture
+  await new test_driver.Actions()
+    .pointerMove(offsetX, offsetY, {origin: num})
+    .pointerDown()
+    .send();
+  await new Promise(requestAnimationFrame);
+
+  fieldset.moveBefore(legend, null);
+  document.body.appendChild(iframe);
+  await new Promise(requestAnimationFrame);
+  document.documentElement.classList.remove('test-wait');
+}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/moveBefore-range-iframe-crash.html b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/moveBefore-range-iframe-crash.html
new file mode 100644
index 0000000..abde4a8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/dom/nodes/moveBefore/moveBefore-range-iframe-crash.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html class="test-wait">
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://issues.chromium.org/issues/523748081">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<style>
+  #slider { width: 400px; height: 30px; }
+</style>
+
+<legend id=legend1>legend1</legend>
+
+<fieldset id=fs disabled>
+  <legend id=legend2>
+    <input type=range id=slider min=0 max=100 value=50>
+  </legend>
+</fieldset>
+
+<iframe id=iframe srcdoc="<body>iframe</body>"></iframe>
+
+<script>
+window.onload = async () => {
+  const slider = document.getElementById("slider");
+  const fs = document.getElementById("fs");
+  const legend1 = document.getElementById("legend1");
+  const legend2 = document.getElementById("legend2");
+  const iframe = document.getElementById("iframe");
+
+  await new Promise(requestAnimationFrame);
+
+  slider.addEventListener("change", () => {
+    iframe.remove();
+  }, { once: true });
+
+  slider.addEventListener("input", () => {
+    fs.moveBefore(legend1, legend2);
+    document.body.appendChild(iframe);
+    document.documentElement.classList.remove('test-wait');
+  }, { once: true });
+
+  const rect = slider.getBoundingClientRect();
+  const offsetX = Math.round(rect.width * 0.4);
+  const offsetY = 0;
+
+  await new test_driver.Actions()
+    .pointerMove(offsetX, offsetY, {origin: slider})
+    .pointerDown()
+    .pause(50)
+    .pointerMove(offsetX + 5, offsetY, {origin: slider})
+    .pointerUp()
+    .send();
+};
+</script>
Loading diff…

Original Bug Report

reported by rj...@google.com

UAF via synchronous 'change' event during moveBefore atomic move

Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: The moveBefore() API sets a StatePreservingAtomicMoveInProgress flag to suppress script execution and frame detachment. However, if a range input becomes disabled during the move, a ‘change’ event is dispatched synchronously, allowing JavaScript to execute while security invariants are suspended.

Affected files:

  • third_party/blink/renderer/core/html/forms/range_input_type.cc

Estimated timestamp from git blame: Unknown (Google3 checkout)

Summary

A potential vulnerability in Blink allows synchronous JavaScript execution during an atomic DOM move (the moveBefore() API). When an <input type="range"> is moved such that its disabled state changes (e.g., inside a disabled <fieldset>), it may trigger a change event synchronously. This violates the StatePreservingAtomicMoveInProgress invariant, which is designed to ensure that no script runs during the atomic operation. Executing script while this flag is active allows an attacker to bypass security checks and cause Use-After-Free (UAF) via orphaned frames.

Technical Details

When the moveBefore() API is invoked, Node::moveBefore() sets the StatePreservingAtomicMoveInProgress flag on the Document. During the insertion phase, ChildrenChanged() is called on ancestor elements.

If the parent is an HTMLFieldSetElement, HTMLFieldSetElement::ChildrenChanged() iterates over its descendants to update their disabled state. If a <input type="range"> transitions to a disabled state, it calls RangeInputType::DisabledAttributeChanged(). This method unconditionally calls GetSliderThumbElement()->StopDragging().

SliderThumbElement::StopDragging() terminates the drag and invokes HostInput()->DispatchFormControlChangeEvent(). Because moveBefore() intentionally does not establish an EventQueueScope (under the assumption that no script can run during atomic moves), the ScopedEventQueue has a scoping level of 0. Consequently, ScopedEventQueue::EnqueueEvent() falls back to synchronous dispatch via EventDispatcher::DispatchEvent().

Impact

The StatePreservingAtomicMoveInProgress flag is used to bypass critical security checks in HTMLFrameOwnerElement and ChildFrameDisconnector. It assumes the DOM is in a controlled, intermediate state. By executing a change event listener during this window, an attacker can manipulate the DOM (e.g., iframe.remove()). The frame is removed from the DOM tree, but because the flag is true, ClearContentFrame() and ChildFrameDisconnector are bypassed. This leaves the frame detached from the DOM but still active in the FrameTree (an orphaned frame), which historically leads to Use-After-Free (UAF) and renderer compromise.

Potential Attack Scenario

Note: These are suggested steps; our tooling agent does not have the ability to run code to confirm a working PoC.

  1. An attacker creates a disabled <fieldset> containing a <legend> (L1). Inside L1, they place an <input type="range" id="slider"> (which remains enabled per HTML spec).
  2. The attacker creates an unrelated <iframe> elsewhere in the document to target for orphaning.
  3. The attacker adds a change event listener to the slider that calls iframe.remove().
  4. The user clicks and drags the slider thumb (mousedown), initiating in_drag_mode_.
  5. During the drag, a mousemove listener on the document executes. It calls fieldset.moveBefore(L0, L1) to insert a new legend L0 before L1.
  6. During the atomic move, L1 is no longer the first legend, so the <fieldset> disabled state now applies to the slider.
  7. HTMLFieldSetElement::ChildrenChanged() updates the slider to disabled. StopDragging() is called, which synchronously fires the change event.
  8. The attacker’s change event listener executes while StatePreservingAtomicMoveInProgress is true.
  9. The iframe.remove() call succeeds, but frame detachment is bypassed, creating an orphaned frame.

Recommendation

Modify RangeInputType::DisabledAttributeChanged() or SliderThumbElement::StopDragging() to queue the event if an atomic move is in progress, or wrap the moveBefore() insertion logic in an EventQueueScope to ensure events dispatched during DOM mutations are deferred until the atomic move completes.

Evaluated with Chrome root at commit: 65b3256311f3ab6fb9870eaa522de7e6dd2663bb


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.

View on issue tracker