CVE-2026-76042
Overview
Background
- `CompoundImageBacking`
- a GPU shared-image backing composed of several “element” sub-backings (e.g. shared-memory and GPU elements) that must be kept in sync so any accessed backing sees the latest content.
- Permanent vs. transient element
- permanent elements are the long-lived sub-backings stored in the compound backing, whereas a transient backing is a temporary target that must be initialized (“synced”) from whichever permanent element holds the latest content before it is used.
- `NotifyBeginAccess` / `NotifyEndAccess`
- hooks invoked when a representation begins/ends accessing a backing; begin-access synchronizes the target from the latest-content element, and end-access proactively copies newly written content back to a permanent element.
- `GetElementWithLatestContent()`
- returns the permanent element whose
content_id_matcheslatest_content_id_, ornullptrif none currently holds the latest content.
Root Cause Analysis
In CompoundImageBacking::NotifyBeginAccess (in compound_image_backing.cc), the code obtains the source of truth via ElementHolder* latest_content_element = GetElementWithLatestContent(); and then synchronizes the destination backing from it. If a transient backing had been written but the proactive copy-back in NotifyEndAccess failed, no permanent element carried the latest content id, so GetElementWithLatestContent() returned nullptr.
Pre-patch, the null result was not checked before the sync block, and the sync was silently skipped while the access was still allowed to proceed — letting a caller read/use a destination (e.g. the GPU) backing that was never initialized with valid content.
The fix inserts an early if (!latest_content_element) guard immediately after the call that logs an error and returns false, so the access is aborted exactly like the existing CopyImage()-failure handling; crucially, it does not advance content versioning, so a later Update() (for SHM-backed images) can re-establish a latest-content element and let access recover. The regression test AccessFailsWhenLatestContentUnavailable drives a transient write with no successful copy-back, asserts that neither SHM nor GPU reports latest content, verifies the subsequent GPU read fails and no upload occurred, then confirms access succeeds again after Update().
GetElementWithLatestContent() without handling the nullptr case, allowing access to proceed against an unsynchronized (uninitialized) backing; the fix adds an early return false on nullptr before the sync so the caller aborts the access.Attack Path
- Set up a compound backing
A client creates a
CompoundImageBackingwith GPU and shared-memory elements and produces a GPU representation of it. - Write to a transient backing
A write access targets a transient backing;
NotifyBeginAccesssyncs it from shared memory and advances the content version. - Fail the copy-back on end access
NotifyEndAccessruns but its proactive copy of the transient content back to a permanent element fails, so no permanent element ends up holding the latest content id. - Begin access with no latest-content element
On the next access,
GetElementWithLatestContent()returnsnullptr; pre-patch the sync block was skipped but access still proceeded. - Use of uninitialized resource The caller reads/uses the never-initialized destination (GPU) backing, exposing uninitialized GPU memory contents (inferred; the diff shows the skipped sync and permitted access, not the concrete disclosure sink).
Impact Assessment
(inferred). The precondition is a real-world copy-back failure path (the test simulates it), after which access continues to fail until Update() or resource re-creation.Changed Functions
| Function | Change | Notes |
|---|---|---|
ifgpu/command_buffer/service/shared_image/compound_image_backing.cc |
modified | |
TEST_Fgpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc |
modified |
Files Changed
gpu/command_buffer/service/shared_image/compound_image_backing_unittest.ccgpu/command_buffer/service/shared_image/compound_image_backing.cc
Audit Directions
- Unchecked "latest/source" lookups feeding a syncSearch for calls returning an optional/pointer source element (like
GetElementWithLatestContent()) whose result is used to synchronize a destination without anullptr/absent check, letting access proceed on unsynchronized data. - Silent skip vs. hard fail on sync failureAudit access/begin hooks where a failed or skipped initialization/copy still returns success; the invariant should be that any failure to establish latest content aborts the access (as
CopyImage()failure already did here). - Proactive copy-back failure handlingReview other backings where end-access copy-back can fail, and confirm that a later access cannot observe partially-initialized or stale state instead of failing safely.
Patch
From a73a143f694c18300b9d87d3d489cddec4124f73 Mon Sep 17 00:00:00 2001
From: vikas soni <vikassoni@chromium.org>
Date: Wed, 22 Jul 2026 11:56:25 -0700
Subject: [PATCH] [GPU Security] Fail CompoundImageBacking access when no latest element.
CompoundImageBacking::NotifyBeginAccess synchronizes the target backing
from the permanent element holding the latest content. If a transient
backing was written but its proactive copy-back in NotifyEndAccess
failed, no permanent element carries the latest content id and
GetElementWithLatestContent() returns nullptr. The sync block was
silently skipped and the access was allowed to proceed against an
unsynchronized backing.
Return false in this case, matching the existing handling for
CopyImage() failure, so the caller aborts the access. Content versioning
is left untouched so a later Update() can restore access. Note that if
there is no SHM backing (e.g. GPU-only backings) or no Update() occurs,
subsequent access calls (including writes) will continue to fail,
requiring client-level context/resource re-creation.
Add a regression test that drives a transient write without a successful
copy-back and verifies read access is refused.
Bug: 536460270
Change-Id: I826b4a872bab19d9532db5f51ca17f137432e4a1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8128128
Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org>
Commit-Queue: vikas soni <vikassoni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1666517}
---
diff --git a/gpu/command_buffer/service/shared_image/compound_image_backing.cc b/gpu/command_buffer/service/shared_image/compound_image_backing.cc
index 95c3fff3..65bbf02e 100644
--- a/gpu/command_buffer/service/shared_image/compound_image_backing.cc
+++ b/gpu/command_buffer/service/shared_image/compound_image_backing.cc
@@ -1256,6 +1256,20 @@
// it's a transient backing that needs to be initialized. We must find the
// permanent element that currently holds the latest content and copy from it.
ElementHolder* latest_content_element = GetElementWithLatestContent();
+ if (!latest_content_element) {
+ // No permanent element holds the most recent content, so the destination
+ // backing cannot be synchronized. This can happen if a transient backing
+ // was written to but its content could not be copied back to a permanent
+ // element on end access. Do not advance versioning so access can recover if
+ // an element re-establishes the latest content (e.g. via Update() for SHM
+ // backings). Note that if there is no SHM backing (e.g. GPU-only backings)
+ // or no Update() occurs, subsequent access calls (including writes) will
+ // continue to fail, requiring client-level context/resource re-creation.
+ LOG(ERROR) << "No element with latest content available for sync to "
+ << backing->GetName();
+ return false;
+ }
+
bool updated_backing = false;
bool copy_succeeded = false;
diff --git a/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc b/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc
index e952d7e..c088b6ea 100644
--- a/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc
+++ b/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc
@@ -507,6 +507,71 @@
EXPECT_TRUE(GetGpuHasLatestContent(compound_backing));
}
+TEST_F(CompoundImageBackingTest, AccessFailsWhenLatestContentUnavailable) {
+ auto backing = CreateCompoundBacking(
+ {SHARED_IMAGE_USAGE_GLES2_READ, SHARED_IMAGE_USAGE_DISPLAY_READ});
+ auto* compound_backing = static_cast<CompoundImageBacking*>(backing.get());
+
+ auto factory_rep =
+ manager_.Register(std::move(backing), &memory_type_tracker_);
+
+ auto gl_rep = manager_.ProduceGLTexturePassthrough(
+ compound_backing->mailbox(), &memory_type_tracker_);
+ ASSERT_TRUE(gl_rep);
+ ASSERT_TRUE(HasGpuBacking(compound_backing));
+ auto* gpu_backing = GetGpuBacking(compound_backing);
+
+ // Simulate a write to a transient backing that is not stored as a permanent
+ // element. Begin access syncs it from shared memory and advances the content
+ // version.
+ auto transient = std::make_unique<TestImageBacking>(
+ compound_backing->mailbox(),
+ SharedImageInfo(compound_backing->format(), compound_backing->size(),
+ compound_backing->color_space(),
+ compound_backing->surface_origin(),
+ compound_backing->alpha_type(), compound_backing->usage(),
+ "Transient"),
+ kTestBackingSize);
+ EXPECT_TRUE(compound_backing->NotifyBeginAccess(
+ transient.get(), RepresentationAccessMode::kWrite,
+ SharedImageAccessStream::kSkia));
+ EXPECT_TRUE(transient->GetUploadFromMemoryCalledAndReset());
+
+ // End access without the transient content being synced back to any
+ // permanent element (as happens when the proactive copy in end access
+ // fails), so no element holds the latest content version.
+ compound_backing->NotifyEndAccess(transient.get(),
+ RepresentationAccessMode::kWrite);
+ transient.reset();
+
+ EXPECT_FALSE(GetShmHasLatestContent(compound_backing));
+ EXPECT_FALSE(GetGpuHasLatestContent(compound_backing));
+
+ // A subsequent read on the GPU backing must not proceed since there is no
+ // element to sync content from and the GPU backing was never initialized.
+ {
+ auto gl_access = gl_rep->BeginScopedAccess(
+ GLTextureImageRepresentationBase::kReadAccessMode,
+ SharedImageRepresentation::AllowUnclearedAccess::kNo);
+ EXPECT_FALSE(gl_access);
+ }
+ EXPECT_FALSE(gpu_backing->GetUploadFromMemoryCalledAndReset());
+ EXPECT_FALSE(GetGpuHasLatestContent(compound_backing));
+
+ // After the shared memory element is marked as the latest via Update(),
+ // access should succeed again.
+ compound_backing->Update(nullptr);
+ EXPECT_TRUE(GetShmHasLatestContent(compound_backing));
+ {
+ auto gl_access = gl_rep->BeginScopedAccess(
+ GLTextureImageRepresentationBase::kReadAccessMode,
+ SharedImageRepresentation::AllowUnclearedAccess::kNo);
+ EXPECT_TRUE(gl_access);
+ }
+ EXPECT_TRUE(gpu_backing->GetUploadFromMemoryCalledAndReset());
+ EXPECT_TRUE(GetGpuHasLatestContent(compound_backing));
+}
+
TEST_F(CompoundImageBackingTest, LazyAllocationFailsCreate) {
auto backing = CreateCompoundBacking({SHARED_IMAGE_USAGE_GLES2_READ});
auto* compound_backing = static_cast<CompoundImageBacking*>(backing.get());
Regression Test / PoC
diff --git a/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc b/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc
index e952d7e..c088b6ea 100644
--- a/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc
+++ b/gpu/command_buffer/service/shared_image/compound_image_backing_unittest.cc
@@ -507,6 +507,71 @@
EXPECT_TRUE(GetGpuHasLatestContent(compound_backing));
}
+TEST_F(CompoundImageBackingTest, AccessFailsWhenLatestContentUnavailable) {
+ auto backing = CreateCompoundBacking(
+ {SHARED_IMAGE_USAGE_GLES2_READ, SHARED_IMAGE_USAGE_DISPLAY_READ});
+ auto* compound_backing = static_cast<CompoundImageBacking*>(backing.get());
+
+ auto factory_rep =
+ manager_.Register(std::move(backing), &memory_type_tracker_);
+
+ auto gl_rep = manager_.ProduceGLTexturePassthrough(
+ compound_backing->mailbox(), &memory_type_tracker_);
+ ASSERT_TRUE(gl_rep);
+ ASSERT_TRUE(HasGpuBacking(compound_backing));
+ auto* gpu_backing = GetGpuBacking(compound_backing);
+
+ // Simulate a write to a transient backing that is not stored as a permanent
+ // element. Begin access syncs it from shared memory and advances the content
+ // version.
+ auto transient = std::make_unique<TestImageBacking>(
+ compound_backing->mailbox(),
+ SharedImageInfo(compound_backing->format(), compound_backing->size(),
+ compound_backing->color_space(),
+ compound_backing->surface_origin(),
+ compound_backing->alpha_type(), compound_backing->usage(),
+ "Transient"),
+ kTestBackingSize);
+ EXPECT_TRUE(compound_backing->NotifyBeginAccess(
+ transient.get(), RepresentationAccessMode::kWrite,
+ SharedImageAccessStream::kSkia));
+ EXPECT_TRUE(transient->GetUploadFromMemoryCalledAndReset());
+
+ // End access without the transient content being synced back to any
+ // permanent element (as happens when the proactive copy in end access
+ // fails), so no element holds the latest content version.
+ compound_backing->NotifyEndAccess(transient.get(),
+ RepresentationAccessMode::kWrite);
+ transient.reset();
+
+ EXPECT_FALSE(GetShmHasLatestContent(compound_backing));
+ EXPECT_FALSE(GetGpuHasLatestContent(compound_backing));
+
+ // A subsequent read on the GPU backing must not proceed since there is no
+ // element to sync content from and the GPU backing was never initialized.
+ {
+ auto gl_access = gl_rep->BeginScopedAccess(
+ GLTextureImageRepresentationBase::kReadAccessMode,
+ SharedImageRepresentation::AllowUnclearedAccess::kNo);
+ EXPECT_FALSE(gl_access);
+ }
+ EXPECT_FALSE(gpu_backing->GetUploadFromMemoryCalledAndReset());
+ EXPECT_FALSE(GetGpuHasLatestContent(compound_backing));
+
+ // After the shared memory element is marked as the latest via Update(),
+ // access should succeed again.
+ compound_backing->Update(nullptr);
+ EXPECT_TRUE(GetShmHasLatestContent(compound_backing));
+ {
+ auto gl_access = gl_rep->BeginScopedAccess(
+ GLTextureImageRepresentationBase::kReadAccessMode,
+ SharedImageRepresentation::AllowUnclearedAccess::kNo);
+ EXPECT_TRUE(gl_access);
+ }
+ EXPECT_TRUE(gpu_backing->GetUploadFromMemoryCalledAndReset());
+ EXPECT_TRUE(GetGpuHasLatestContent(compound_backing));
+}
+
TEST_F(CompoundImageBackingTest, LazyAllocationFailsCreate) {
auto backing = CreateCompoundBacking({SHARED_IMAGE_USAGE_GLES2_READ});
auto* compound_backing = static_cast<CompoundImageBacking*>(backing.get());
Original Bug Report
Potential uninitialized VRAM read in CompoundImageBacking via failed proactive copy-back
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: A vulnerability in CompoundImageBacking allows a compromised renderer to read uninitialized GPU VRAM. If a transient backing’s proactive copy-back fails under memory pressure, subsequent reads skip synchronization, allowing the read of uninitialized textures that bypass the IsCleared() gate.
Affected files:
gpu/command_buffer/service/shared_image/compound_image_backing.ccgpu/command_buffer/service/shared_image/wrapped_sk_image_backing.ccgpu/command_buffer/service/shared_image/shared_image_representation.cc
Estimated timestamp from git blame: 2026-05-07
1. Summary of the Issue (Meant for Human Triage)
A potential security vulnerability exists in CompoundImageBacking due to an oversight in handling proactive copy-back failures for transient backings. This vulnerability allows a compromised renderer to bypass synchronization and read physically uninitialized, driver-recycled GPU VRAM, presenting a significant cross-origin data exposure risk (GPU-XO).
When the features::kUseDynamicBackingAllocations flag is enabled (currently FEATURE_DISABLED_BY_DEFAULT), CompoundImageBacking supports dynamic lazy creation of GPU backings. If a transient backing is created (e.g., inside a thread-safe container like DrDC/WebView) and written to, its content must be proactively copied back to permanent backings inside NotifyEndAccess. If this proactive copy-back fails (which an attacker can induce by causing staging-buffer allocation failures via memory-pressure spraying), the code logs an error and continues without updating the permanent backing’s content_id_.
Subsequently, a read access on a lazily allocated GPU backing triggers NotifyBeginAccess. Because no permanent backing matches the latest_content_id_, GetElementWithLatestContent() returns nullptr. This causes the entire synchronization block to be skipped. NotifyBeginAccess returns true (success). Because the CompoundImageBacking container was artificially marked fully cleared upon creation with a shared memory backing, the outer IsCleared() validation passes. The renderer then reads directly from the physically uninitialized backend GPU texture, leaking cross-origin graphical content from recycled driver VRAM.
2. Proof-of-Concept & Detailed Execution Flow
Note: Our tooling agent does not have the ability to run code. The steps below are a potential, theoretically verified sequence based on static analysis of the codebase.
Step-by-Step Sequence:
- Precondition: The feature
features::kUseDynamicBackingAllocationsmust be enabled. - Container Creation: A compromised renderer (A-RENDERER) sends a
mojom::DeferredSharedImageRequest{kCreateSharedImageWithBuffer}IPC over itsGpuChannelto create aCompoundImageBackingbacked by aSHARED_MEMORY_BUFFER. - The renderer specifies usage flags (e.g.,
SHARED_IMAGE_USAGE_DISPLAY_READ | SHARED_IMAGE_USAGE_CPU_WRITE_ONLY) causingSharedImageFactory::CreateSharedImageto fall back toCompoundImageBacking::Create. - During initialization,
CompoundImageBacking::ComputeIsThreadSafeevaluatesfactory->shared_image_manager_->display_context_on_another_thread()totrue(e.g., on DrDC or WebView). This forcesis_thread_safetotrue, making theCompoundImageBackinga thread-safe container. - The constructor initializes the primary shared memory backing as
elements_[0], setshas_shm_backing_ = true, and crucially marks the compound container as fully cleared viaSetClearedRectInternal(gfx::Rect(size))(compound_image_backing.cc:1157). - The container initializes
latest_content_id_ = 1andelements_[0].content_id_ = 1. - Transient Write Access: The renderer initiates a Write access on a stream (e.g.,
kSkia) that triggers dynamic backing allocation. GetOrAllocateBackingfalls back toSharedImageFactoryto dynamically allocate a new GPU backing (CreateBackingFromBackingFactory).- Because the compound container is thread-safe but the new GPU backing is not, the code treats it as a transient backing (
compound_image_backing.cc:2038). It is returned viaout_transient_backingand not added to the permanentelements_list. - The wrapper calls
NotifyBeginAccesson the transient backing withmode = kWrite. GetElementWithLatestContent()returnselements_[0].copy_manager_->CopyImagesuccessfully syncs data.latest_content_id_increments to2. Because it is transient,access_elementisnullptr, so no permanent element’scontent_id_is updated.- Induced Copy Failure: The wrapper calls
EndWriteAccess, invokingNotifyEndAccess(backing, kWrite). This detects the transient backing and attempts a proactive copy-back toelements_[0](compound_image_backing.cc:1361). - The attacker concurrently induces extreme GPU memory pressure (e.g., spraying SharedImages), exhausting staging/transfer buffers. The
copy_manager_->CopyImagefails. - The code logs
"DCSI: Proactive copy ... failed."but critically continues without updatingelements_[0].content_id_to2(compound_image_backing.cc:1370). The transient backing is destroyed.latest_content_id_is2, but the permanent element has1. - Uninitialized Read: The renderer initiates a Read access (e.g.,
ReadbackARGBImagePixelsINTERNALImmediate) using a stream that requires a new permanent GPU backing (e.g.,GLTextureImageBacking). GetOrAllocateBackingallocates the new GPU backing. Becausehas_shm_backing_istrue,backing->SetCleared()is called unconditionally (compound_image_backing.cc:2106).- This prematurely marks the new backing as physically initialized, despite containing recycled, uninitialized driver VRAM. It is added as
elements_[1]withcontent_id_ = 0. NotifyBeginAccessis called withmode = kRead.GetElementWithLatestContent()looks for an element withcontent_id_ == 2. Sinceelements_[0]is1andelements_[1]is0, it returnsnullptr(compound_image_backing.cc:1953).- Because
latest_content_elementisnullptr, the physical synchronization block (if (latest_content_element)) is bypassed entirely (compound_image_backing.cc:1262). NotifyBeginAccessreturnstrue(success).- The representation wrapper (e.g.,
SkiaGaneshImageRepresentation::BeginScopedReadAccess) checksIsCleared(). This delegates toCompoundImageBacking::ClearedRect(), which returns the full image bounds set in Step 5. - The gate passes. The renderer reads the newly allocated, physically uninitialized GPU backing. Backend texture allocations (Vulkan, D3D, Metal) do not zero-fill in release builds, exposing recycled driver VRAM to the attacker.
Suggested Fix:
In CompoundImageBacking::NotifyBeginAccess, if latest_content_element returns nullptr but latest_content_id_ > 1 (meaning valid data existed but was lost during a failed proactive copy-back), NotifyBeginAccess should explicitly return false to abort the read. Alternatively, in NotifyEndAccess, if the proactive copy-back fails, the container should be marked into a degraded/invalid state that forces subsequent accesses to fail gracefully.
3. Technical Verification Details (Automated Audit Logs)
> Severity: High (S1)
> Brief Notes / Reasoning:
> The primary variant described in the report is invalid (S4). NotifyBeginAccess is declared as [[nodiscard]] bool, and all representation wrappers (e.g., WrappedSkiaGaneshCompoundImageRepresentation::BeginReadAccess) explicitly check its return value. If CopyImage fails, NotifyBeginAccess returns false, and the wrapper early-returns, safely preventing the read. The report’s claim that it returns void and falls through is incorrect for the current codebase.
>
> However, the secondary sub-variant (latest_content_element == nullptr) is structurally valid. When features::kUseDynamicBackingAllocations is enabled, a transient backing can be created. During a write access on a transient backing, NotifyBeginAccess increments latest_content_id_. If the proactive copy-back to the SHM backing in NotifyEndAccess fails (e.g., due to staging buffer allocation failure from memory pressure), no permanent element’s content_id_ is updated. A subsequent read on a lazily-allocated GPU backing causes GetElementWithLatestContent() to return nullptr. NotifyBeginAccess skips the copy block entirely and returns true. The read proceeds on the GPU backing, which was marked SetCleared() at creation without being initialized. This results in a cross-origin GPU-memory disclosure (S1 - High Severity).
>
> Per the severity guidelines, since the valid variant is behind an off-by-default flag (FEATURE_DISABLED_BY_DEFAULT) with no field trial, we assess the severity AS IF the flag were on (S1), but note Security_Impact-None.
Code Reachability Proofs & Evaluated Logic:
ComputeIsThreadSafeLogic:gpu/command_buffer/service/shared_image/compound_image_backing.cc:928-932if (!is_thread_safe && base::FeatureList::IsEnabled(features::kUseDynamicBackingAllocations)) { is_thread_safe = factory->shared_image_manager_->display_context_on_another_thread(); }GetOrAllocateBackingtransient backing allocation:gpu/command_buffer/service/shared_image/compound_image_backing.cc:2038-2041if (is_thread_safe() && !new_backing->is_thread_safe()) { out_transient_backing = std::move(new_backing); return out_transient_backing.get(); }NotifyEndAccessProactive Copy-Back Failure:gpu/command_buffer/service/shared_image/compound_image_backing.cc:1367-1372if (copy_manager_->CopyImage(backing, dst_backing)) { element.content_id_ = latest_content_id_; } else { LOG(ERROR) << "DCSI: Proactive copy from " << backing->GetName() << " to " << dst_backing->GetName() << " failed."; }NotifyBeginAccessSynchronization Skip:gpu/command_buffer/service/shared_image/compound_image_backing.cc:1258-1262ElementHolder* latest_content_element = GetElementWithLatestContent(); bool updated_backing = false; bool copy_succeeded = false; if (latest_content_element) { // [Bypassed because latest_content_element is nullptr] } // Falls through to: return true;CreateBackingFromBackingFactoryPremature Clear:gpu/command_buffer/service/shared_image/compound_image_backing.cc:2105-2107if (has_shm_backing_) { backing->SetCleared(); }
Environmental Assumptions:
features::kUseDynamicBackingAllocationsmust be explicitly enabled.- Target environments include Vulkan, D3D, or Metal backends where
createBackendTextureallocations are recycled and not zero-filled in Release builds to avoid overhead (wrapped_sk_image_backing.cc:232-237).
Evaluated with Chrome root at commit: b96d2ec58f4f5f92b540a723966b199d6e9951b4
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.