VYPR
Medium severity6.1OSV Advisory· Published Sep 4, 2025· Updated Apr 15, 2026

CVE-2025-55305

CVE-2025-55305

Description

Electron is a framework for writing cross-platform desktop applications using JavaScript, HTML and CSS. In versions below 35.7.5, 36.0.0-alpha.1 through 36.8.0, 37.0.0-alpha.1 through 37.3.1 and 38.0.0-alpha.1 through 38.0.0-beta.6, ASAR Integrity Bypass via resource modification. This only impacts apps that have the embeddedAsarIntegrityValidation and onlyLoadAppFromAsar fuses enabled. Apps without these fuses enabled are not impacted. This issue is fixed in versions 35.7.5, 36.8.1, 37.3.1 and 38.0.0-beta.6.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
electronnpm
< 35.7.535.7.5
electronnpm
>= 36.0.0-alpha.1, < 36.8.136.8.1
electronnpm
>= 37.0.0-alpha.1, < 37.3.137.3.1
electronnpm
>= 38.0.0-alpha.1, < 38.0.0-beta.638.0.0-beta.6

Affected products

1

Patches

5
86d839a881b6

build: correct CHECK syntax (#48106)

https://github.com/electron/electronKeeley HammondAug 19, 2025via osv
1 file changed · +1 1
  • shell/app/electron_main_delegate.cc+1 1 modified
    @@ -213,7 +213,7 @@ void RegisterPathProvider() {
     void ValidateV8Snapshot(v8::StartupData* data) {
       if (data->data &&
           electron::fuses::IsEmbeddedAsarIntegrityValidationEnabled()) {
    -    CHECK(data->raw_size, 0);
    +    CHECK_GT(data->raw_size, 0);
         UNSAFE_BUFFERS({
           base::span<const char> span_data(
               data->data, static_cast<unsigned long>(data->raw_size));
    
3f92511cdecc

fix: ensure snapshot is valid (#48104)

https://github.com/electron/electronKeeley HammondAug 18, 2025via ghsa
5 files changed · +138 1
  • build/checksum_header.py+37 0 added
    @@ -0,0 +1,37 @@
    +#!/usr/bin/env python3
    +
    +import os
    +import sys
    +import hashlib
    +
    +dir_path = os.path.dirname(os.path.realpath(__file__))
    +
    +TEMPLATE_H = """
    +#ifndef ELECTRON_SNAPSHOT_CHECKSUM_H_
    +#define ELECTRON_SNAPSHOT_CHECKSUM_H_
    +
    +namespace electron::snapshot_checksum {
    +
    +const std::string kChecksum = "{checksum}";
    +
    +}  // namespace electron::snapshot_checksum
    +
    +#endif  // ELECTRON_SNAPSHOT_CHECKSUM_H_
    +"""
    +
    +def calculate_sha256(filepath):
    +    sha256_hash = hashlib.sha256()
    +    with open(filepath, "rb") as f:
    +        for byte_block in iter(lambda: f.read(4096), b""):
    +            sha256_hash.update(byte_block)
    +    return sha256_hash.hexdigest()
    +
    +input_file = sys.argv[1]
    +output_file = sys.argv[2]
    +
    +checksum = calculate_sha256(input_file)
    +
    +checksum_h = TEMPLATE_H.replace("{checksum}", checksum)
    +
    +with open(output_file, 'w') as f:
    +    f.write(checksum_h)
    
  • BUILD.gn+12 0 modified
    @@ -518,6 +518,10 @@ source_set("electron_lib") {
         "//v8:v8_libplatform",
       ]
     
    +  if (v8_use_external_startup_data && use_v8_context_snapshot) {
    +    deps += [ ":mksnapshot_checksum_gen" ]
    +  }
    +
       public_deps = [
         "//base",
         "//base:i18n",
    @@ -772,6 +776,14 @@ source_set("electron_lib") {
       }
     }
     
    +action("mksnapshot_checksum_gen") {
    +  script = "build/checksum_header.py"
    +  outputs = [ "$target_gen_dir/snapshot_checksum.h" ]
    +  inputs = [ "$root_out_dir/$v8_context_snapshot_filename" ]
    +  args = rebase_path(inputs) + rebase_path(outputs)
    +  deps = [ "//tools/v8_context_snapshot" ]
    +}
    +
     electron_paks("packed_resources") {
       if (is_mac) {
         output_dir = "$root_gen_dir/electron_repack"
    
  • patches/chromium/feat_add_support_for_embedder_snapshot_validation.patch+67 0 added
    @@ -0,0 +1,67 @@
    +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
    +From: Samuel Attard <sattard@anthropic.com>
    +Date: Fri, 15 Aug 2025 14:58:12 -0700
    +Subject: feat: add support for embedder snapshot validation
    +
    +IsValid is not exposed despite being commented as for embedders, this exposes something that works for us.
    +
    +diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc
    +index e07bdaeccecc8015462e35d5cf4606335e2e962c..28b133626cf3488dee6f43bfd0ac9b6b14ed3980 100644
    +--- a/gin/v8_initializer.cc
    ++++ b/gin/v8_initializer.cc
    +@@ -75,11 +75,23 @@ bool GenerateEntropy(unsigned char* buffer, size_t amount) {
    +   return true;
    + }
    + 
    ++static base::RepeatingCallback<void(v8::StartupData*)>& SnapshotValidator() {
    ++  static base::NoDestructor<base::RepeatingCallback<void(v8::StartupData*)>>
    ++      validator(
    ++          base::BindRepeating([](v8::StartupData* data) -> void { /* empty */ }));
    ++  return *validator;
    ++}
    ++
    ++void SetV8SnapshotValidatorInner(const base::RepeatingCallback<void(v8::StartupData*)>& callback) {
    ++  SnapshotValidator() = std::move(callback);
    ++}
    ++
    + void GetMappedFileData(base::MemoryMappedFile* mapped_file,
    +                        v8::StartupData* data) {
    +   if (mapped_file) {
    +     data->data = reinterpret_cast<const char*>(mapped_file->data());
    +     data->raw_size = static_cast<int>(mapped_file->length());
    ++    SnapshotValidator().Run(data);
    +   } else {
    +     data->data = nullptr;
    +     data->raw_size = 0;
    +@@ -223,6 +235,10 @@ constexpr std::string_view kV8FlagFeaturePrefix = "V8Flag_";
    + 
    + }  // namespace
    + 
    ++void SetV8SnapshotValidator(const base::RepeatingCallback<void(v8::StartupData*)>& callback) {
    ++  SetV8SnapshotValidatorInner(std::move(callback));
    ++}
    ++
    + class V8FeatureVisitor : public base::FeatureVisitor {
    +  public:
    +   void Visit(const std::string& feature_name,
    +diff --git a/gin/v8_initializer.h b/gin/v8_initializer.h
    +index 6f7382cd600cd34916d9382878aee4b469dae5d0..61ed0f46437d2e1abbcebcfb64df06d17c8d9139 100644
    +--- a/gin/v8_initializer.h
    ++++ b/gin/v8_initializer.h
    +@@ -11,6 +11,7 @@
    + 
    + #include "base/files/file.h"
    + #include "base/files/memory_mapped_file.h"
    ++#include "base/functional/callback.h"
    + #include "build/build_config.h"
    + #include "gin/array_buffer.h"
    + #include "gin/gin_export.h"
    +@@ -28,6 +29,8 @@ class StartupData;
    + 
    + namespace gin {
    + 
    ++void SetV8SnapshotValidator(const base::RepeatingCallback<void(v8::StartupData*)>& callback);
    ++
    + class GIN_EXPORT V8Initializer {
    +  public:
    +   // This should be called by IsolateHolder::Initialize().
    
  • patches/chromium/.patches+1 0 modified
    @@ -149,3 +149,4 @@ do_not_check_the_order_of_display_id_order_on_windows.patch
     make_focus_methods_in_webcontentsviewchildframe_notimplemented.patch
     cherry-pick-f1e6422a355c.patch
     fix_resolve_dynamic_background_material_update_issue_on_windows_11.patch
    +feat_add_support_for_embedder_snapshot_validation.patch
    
  • shell/app/electron_main_delegate.cc+21 1 modified
    @@ -23,10 +23,13 @@
     #include "components/content_settings/core/common/content_settings_pattern.h"
     #include "content/public/app/initialize_mojo_core.h"
     #include "content/public/common/content_switches.h"
    +#include "crypto/hash.h"
     #include "electron/buildflags/buildflags.h"
     #include "electron/fuses.h"
     #include "electron/mas.h"
    +#include "electron/snapshot_checksum.h"
     #include "extensions/common/constants.h"
    +#include "gin/v8_initializer.h"
     #include "ipc/ipc_buildflags.h"
     #include "sandbox/policy/switches.h"
     #include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
    @@ -49,6 +52,7 @@
     #include "third_party/abseil-cpp/absl/types/variant.h"
     #include "ui/base/resource/resource_bundle.h"
     #include "ui/base/ui_base_switches.h"
    +#include "v8/include/v8-snapshot.h"
     
     #if BUILDFLAG(IS_MAC)
     #include "shell/app/electron_main_delegate_mac.h"
    @@ -206,6 +210,20 @@ void RegisterPathProvider() {
                                           PATH_END);
     }
     
    +void ValidateV8Snapshot(v8::StartupData* data) {
    +  if (data->data &&
    +      electron::fuses::IsEmbeddedAsarIntegrityValidationEnabled()) {
    +    CHECK_GT(data->raw_size, 0);
    +    UNSAFE_BUFFERS({
    +      base::span<const char> span_data(
    +          data->data, static_cast<unsigned long>(data->raw_size));
    +      CHECK(base::ToLowerASCII(base::HexEncode(
    +                crypto::hash::Sha256(base::as_bytes(span_data)))) ==
    +            electron::snapshot_checksum::kChecksum);
    +    })
    +  }
    +}
    +
     }  // namespace
     
     std::string LoadResourceBundle(const std::string& locale) {
    @@ -229,7 +247,9 @@ std::string LoadResourceBundle(const std::string& locale) {
       return loaded_locale;
     }
     
    -ElectronMainDelegate::ElectronMainDelegate() = default;
    +ElectronMainDelegate::ElectronMainDelegate() {
    +  gin::SetV8SnapshotValidator(base::BindRepeating(&ValidateV8Snapshot));
    +}
     
     ElectronMainDelegate::~ElectronMainDelegate() = default;
     
    
23a02934510f

fix: ensure snapshot is valid (#48103)

https://github.com/electron/electronKeeley HammondAug 18, 2025via ghsa
5 files changed · +140 1
  • build/checksum_header.py+37 0 added
    @@ -0,0 +1,37 @@
    +#!/usr/bin/env python3
    +
    +import os
    +import sys
    +import hashlib
    +
    +dir_path = os.path.dirname(os.path.realpath(__file__))
    +
    +TEMPLATE_H = """
    +#ifndef ELECTRON_SNAPSHOT_CHECKSUM_H_
    +#define ELECTRON_SNAPSHOT_CHECKSUM_H_
    +
    +namespace electron::snapshot_checksum {
    +
    +const std::string kChecksum = "{checksum}";
    +
    +}  // namespace electron::snapshot_checksum
    +
    +#endif  // ELECTRON_SNAPSHOT_CHECKSUM_H_
    +"""
    +
    +def calculate_sha256(filepath):
    +    sha256_hash = hashlib.sha256()
    +    with open(filepath, "rb") as f:
    +        for byte_block in iter(lambda: f.read(4096), b""):
    +            sha256_hash.update(byte_block)
    +    return sha256_hash.hexdigest()
    +
    +input_file = sys.argv[1]
    +output_file = sys.argv[2]
    +
    +checksum = calculate_sha256(input_file)
    +
    +checksum_h = TEMPLATE_H.replace("{checksum}", checksum)
    +
    +with open(output_file, 'w') as f:
    +    f.write(checksum_h)
    
  • BUILD.gn+12 0 modified
    @@ -518,6 +518,10 @@ source_set("electron_lib") {
         "//v8:v8_libplatform",
       ]
     
    +  if (v8_use_external_startup_data && use_v8_context_snapshot) {
    +    deps += [ ":mksnapshot_checksum_gen" ]
    +  }
    +
       public_deps = [
         "//base",
         "//base:i18n",
    @@ -772,6 +776,14 @@ source_set("electron_lib") {
       }
     }
     
    +action("mksnapshot_checksum_gen") {
    +  script = "build/checksum_header.py"
    +  outputs = [ "$target_gen_dir/snapshot_checksum.h" ]
    +  inputs = [ "$root_out_dir/$v8_context_snapshot_filename" ]
    +  args = rebase_path(inputs) + rebase_path(outputs)
    +  deps = [ "//tools/v8_context_snapshot" ]
    +}
    +
     electron_paks("packed_resources") {
       if (is_mac) {
         output_dir = "$root_gen_dir/electron_repack"
    
  • patches/chromium/feat_add_support_for_embedder_snapshot_validation.patch+67 0 added
    @@ -0,0 +1,67 @@
    +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
    +From: Samuel Attard <sattard@anthropic.com>
    +Date: Fri, 15 Aug 2025 14:58:12 -0700
    +Subject: feat: add support for embedder snapshot validation
    +
    +IsValid is not exposed despite being commented as for embedders, this exposes something that works for us.
    +
    +diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc
    +index 03c9bc18566794a668981bba6235b226e07eff74..9ad6909dc6084202e9227801a9d200355b30d164 100644
    +--- a/gin/v8_initializer.cc
    ++++ b/gin/v8_initializer.cc
    +@@ -75,11 +75,23 @@ bool GenerateEntropy(unsigned char* buffer, size_t amount) {
    +   return true;
    + }
    + 
    ++static base::RepeatingCallback<void(v8::StartupData*)>& SnapshotValidator() {
    ++  static base::NoDestructor<base::RepeatingCallback<void(v8::StartupData*)>>
    ++      validator(
    ++          base::BindRepeating([](v8::StartupData* data) -> void { /* empty */ }));
    ++  return *validator;
    ++}
    ++
    ++void SetV8SnapshotValidatorInner(const base::RepeatingCallback<void(v8::StartupData*)>& callback) {
    ++  SnapshotValidator() = std::move(callback);
    ++}
    ++
    + void GetMappedFileData(base::MemoryMappedFile* mapped_file,
    +                        v8::StartupData* data) {
    +   if (mapped_file) {
    +     data->data = reinterpret_cast<const char*>(mapped_file->data());
    +     data->raw_size = static_cast<int>(mapped_file->length());
    ++    SnapshotValidator().Run(data);
    +   } else {
    +     data->data = nullptr;
    +     data->raw_size = 0;
    +@@ -223,6 +235,10 @@ constexpr std::string_view kV8FlagFeaturePrefix = "V8Flag_";
    + 
    + }  // namespace
    + 
    ++void SetV8SnapshotValidator(const base::RepeatingCallback<void(v8::StartupData*)>& callback) {
    ++  SetV8SnapshotValidatorInner(std::move(callback));
    ++}
    ++
    + class V8FeatureVisitor : public base::FeatureVisitor {
    +  public:
    +   void Visit(const std::string& feature_name,
    +diff --git a/gin/v8_initializer.h b/gin/v8_initializer.h
    +index 6f7382cd600cd34916d9382878aee4b469dae5d0..61ed0f46437d2e1abbcebcfb64df06d17c8d9139 100644
    +--- a/gin/v8_initializer.h
    ++++ b/gin/v8_initializer.h
    +@@ -11,6 +11,7 @@
    + 
    + #include "base/files/file.h"
    + #include "base/files/memory_mapped_file.h"
    ++#include "base/functional/callback.h"
    + #include "build/build_config.h"
    + #include "gin/array_buffer.h"
    + #include "gin/gin_export.h"
    +@@ -28,6 +29,8 @@ class StartupData;
    + 
    + namespace gin {
    + 
    ++void SetV8SnapshotValidator(const base::RepeatingCallback<void(v8::StartupData*)>& callback);
    ++
    + class GIN_EXPORT V8Initializer {
    +  public:
    +   // This should be called by IsolateHolder::Initialize().
    
  • patches/chromium/.patches+1 0 modified
    @@ -142,3 +142,4 @@ chore_grandfather_in_electron_views_and_delegates.patch
     refactor_patch_electron_permissiontypes_into_blink.patch
     fix_add_macos_memory_query_fallback_to_avoid_crash.patch
     fix_resolve_dynamic_background_material_update_issue_on_windows_11.patch
    +feat_add_support_for_embedder_snapshot_validation.patch
    
  • shell/app/electron_main_delegate.cc+23 1 modified
    @@ -19,15 +19,20 @@
     #include "base/logging.h"
     #include "base/path_service.h"
     #include "base/strings/cstring_view.h"
    +#include "base/strings/string_number_conversions.cc"
    +#include "base/strings/string_util_internal.h"
     #include "chrome/common/chrome_paths.h"
     #include "chrome/common/chrome_switches.h"
     #include "components/content_settings/core/common/content_settings_pattern.h"
     #include "content/public/app/initialize_mojo_core.h"
     #include "content/public/common/content_switches.h"
    +#include "crypto/hash.h"
     #include "electron/buildflags/buildflags.h"
     #include "electron/fuses.h"
     #include "electron/mas.h"
    +#include "electron/snapshot_checksum.h"
     #include "extensions/common/constants.h"
    +#include "gin/v8_initializer.h"
     #include "ipc/ipc_buildflags.h"
     #include "sandbox/policy/switches.h"
     #include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
    @@ -50,6 +55,7 @@
     #include "third_party/abseil-cpp/absl/types/variant.h"
     #include "ui/base/resource/resource_bundle.h"
     #include "ui/base/ui_base_switches.h"
    +#include "v8/include/v8-snapshot.h"
     
     #if BUILDFLAG(IS_MAC)
     #include "shell/app/electron_main_delegate_mac.h"
    @@ -208,6 +214,20 @@ void RegisterPathProvider() {
                                           PATH_END);
     }
     
    +void ValidateV8Snapshot(v8::StartupData* data) {
    +  if (data->data &&
    +      electron::fuses::IsEmbeddedAsarIntegrityValidationEnabled()) {
    +    CHECK_GT(data->raw_size, 0);
    +    UNSAFE_BUFFERS({
    +      base::span<const char> span_data(
    +          data->data, static_cast<unsigned long>(data->raw_size));
    +      CHECK(base::ToLowerASCII(base::HexEncode(
    +                crypto::hash::Sha256(base::as_bytes(span_data)))) ==
    +            electron::snapshot_checksum::kChecksum);
    +    })
    +  }
    +}
    +
     }  // namespace
     
     std::string LoadResourceBundle(const std::string& locale) {
    @@ -231,7 +251,9 @@ std::string LoadResourceBundle(const std::string& locale) {
       return loaded_locale;
     }
     
    -ElectronMainDelegate::ElectronMainDelegate() = default;
    +ElectronMainDelegate::ElectronMainDelegate() {
    +  gin::SetV8SnapshotValidator(base::BindRepeating(&ValidateV8Snapshot));
    +}
     
     ElectronMainDelegate::~ElectronMainDelegate() = default;
     
    
2e5a0b7220eb

fix: ensure snapshot is valid (#48102)

https://github.com/electron/electronKeeley HammondAug 18, 2025via ghsa
5 files changed · +140 1
  • build/checksum_header.py+37 0 added
    @@ -0,0 +1,37 @@
    +#!/usr/bin/env python3
    +
    +import os
    +import sys
    +import hashlib
    +
    +dir_path = os.path.dirname(os.path.realpath(__file__))
    +
    +TEMPLATE_H = """
    +#ifndef ELECTRON_SNAPSHOT_CHECKSUM_H_
    +#define ELECTRON_SNAPSHOT_CHECKSUM_H_
    +
    +namespace electron::snapshot_checksum {
    +
    +const std::string kChecksum = "{checksum}";
    +
    +}  // namespace electron::snapshot_checksum
    +
    +#endif  // ELECTRON_SNAPSHOT_CHECKSUM_H_
    +"""
    +
    +def calculate_sha256(filepath):
    +    sha256_hash = hashlib.sha256()
    +    with open(filepath, "rb") as f:
    +        for byte_block in iter(lambda: f.read(4096), b""):
    +            sha256_hash.update(byte_block)
    +    return sha256_hash.hexdigest()
    +
    +input_file = sys.argv[1]
    +output_file = sys.argv[2]
    +
    +checksum = calculate_sha256(input_file)
    +
    +checksum_h = TEMPLATE_H.replace("{checksum}", checksum)
    +
    +with open(output_file, 'w') as f:
    +    f.write(checksum_h)
    
  • BUILD.gn+12 0 modified
    @@ -518,6 +518,10 @@ source_set("electron_lib") {
         "//v8:v8_libplatform",
       ]
     
    +  if (v8_use_external_startup_data && use_v8_context_snapshot) {
    +    deps += [ ":mksnapshot_checksum_gen" ]
    +  }
    +
       public_deps = [
         "//base",
         "//base:i18n",
    @@ -772,6 +776,14 @@ source_set("electron_lib") {
       }
     }
     
    +action("mksnapshot_checksum_gen") {
    +  script = "build/checksum_header.py"
    +  outputs = [ "$target_gen_dir/snapshot_checksum.h" ]
    +  inputs = [ "$root_out_dir/$v8_context_snapshot_filename" ]
    +  args = rebase_path(inputs) + rebase_path(outputs)
    +  deps = [ "//tools/v8_context_snapshot" ]
    +}
    +
     electron_paks("packed_resources") {
       if (is_mac) {
         output_dir = "$root_gen_dir/electron_repack"
    
  • patches/chromium/feat_add_support_for_embedder_snapshot_validation.patch+67 0 added
    @@ -0,0 +1,67 @@
    +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
    +From: Samuel Attard <sattard@anthropic.com>
    +Date: Fri, 15 Aug 2025 14:58:12 -0700
    +Subject: feat: add support for embedder snapshot validation
    +
    +IsValid is not exposed despite being commented as for embedders, this exposes something that works for us.
    +
    +diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc
    +index f83461b3a1aff229164358e53847065ddae5ddf1..12faa71c2e14d2f13ab612526f349e9b027e5d3d 100644
    +--- a/gin/v8_initializer.cc
    ++++ b/gin/v8_initializer.cc
    +@@ -76,11 +76,23 @@ bool GenerateEntropy(unsigned char* buffer, size_t amount) {
    +   return true;
    + }
    + 
    ++static base::RepeatingCallback<void(v8::StartupData*)>& SnapshotValidator() {
    ++  static base::NoDestructor<base::RepeatingCallback<void(v8::StartupData*)>>
    ++      validator(
    ++          base::BindRepeating([](v8::StartupData* data) -> void { /* empty */ }));
    ++  return *validator;
    ++}
    ++
    ++void SetV8SnapshotValidatorInner(const base::RepeatingCallback<void(v8::StartupData*)>& callback) {
    ++  SnapshotValidator() = std::move(callback);
    ++}
    ++
    + void GetMappedFileData(base::MemoryMappedFile* mapped_file,
    +                        v8::StartupData* data) {
    +   if (mapped_file) {
    +     data->data = reinterpret_cast<const char*>(mapped_file->data());
    +     data->raw_size = static_cast<int>(mapped_file->length());
    ++    SnapshotValidator().Run(data);
    +   } else {
    +     data->data = nullptr;
    +     data->raw_size = 0;
    +@@ -225,6 +237,10 @@ constexpr std::string_view kV8FlagParam = "V8FlagParam";
    + 
    + }  // namespace
    + 
    ++void SetV8SnapshotValidator(const base::RepeatingCallback<void(v8::StartupData*)>& callback) {
    ++  SetV8SnapshotValidatorInner(std::move(callback));
    ++}
    ++
    + class V8FeatureVisitor : public base::FeatureVisitor {
    +  public:
    +   void Visit(const std::string& feature_name,
    +diff --git a/gin/v8_initializer.h b/gin/v8_initializer.h
    +index 6f7382cd600cd34916d9382878aee4b469dae5d0..61ed0f46437d2e1abbcebcfb64df06d17c8d9139 100644
    +--- a/gin/v8_initializer.h
    ++++ b/gin/v8_initializer.h
    +@@ -11,6 +11,7 @@
    + 
    + #include "base/files/file.h"
    + #include "base/files/memory_mapped_file.h"
    ++#include "base/functional/callback.h"
    + #include "build/build_config.h"
    + #include "gin/array_buffer.h"
    + #include "gin/gin_export.h"
    +@@ -28,6 +29,8 @@ class StartupData;
    + 
    + namespace gin {
    + 
    ++void SetV8SnapshotValidator(const base::RepeatingCallback<void(v8::StartupData*)>& callback);
    ++
    + class GIN_EXPORT V8Initializer {
    +  public:
    +   // This should be called by IsolateHolder::Initialize().
    
  • patches/chromium/.patches+1 0 modified
    @@ -137,3 +137,4 @@ build_set_mac_sdk_minimum_to_10.patch
     fix_add_macos_memory_query_fallback_to_avoid_crash.patch
     fix_resolve_dynamic_background_material_update_issue_on_windows_11.patch
     chore_restore_some_deprecated_wrapper_utility_in_gin.patch
    +feat_add_support_for_embedder_snapshot_validation.patch
    
  • shell/app/electron_main_delegate.cc+23 1 modified
    @@ -19,15 +19,20 @@
     #include "base/logging.h"
     #include "base/path_service.h"
     #include "base/strings/cstring_view.h"
    +#include "base/strings/string_number_conversions.cc"
    +#include "base/strings/string_util_internal.h"
     #include "chrome/common/chrome_paths.h"
     #include "chrome/common/chrome_switches.h"
     #include "components/content_settings/core/common/content_settings_pattern.h"
     #include "content/public/app/initialize_mojo_core.h"
     #include "content/public/common/content_switches.h"
    +#include "crypto/hash.h"
     #include "electron/buildflags/buildflags.h"
     #include "electron/fuses.h"
     #include "electron/mas.h"
    +#include "electron/snapshot_checksum.h"
     #include "extensions/common/constants.h"
    +#include "gin/v8_initializer.h"
     #include "sandbox/policy/switches.h"
     #include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
     #include "shell/app/command_line_args.h"
    @@ -49,6 +54,7 @@
     #include "third_party/abseil-cpp/absl/types/variant.h"
     #include "ui/base/resource/resource_bundle.h"
     #include "ui/base/ui_base_switches.h"
    +#include "v8/include/v8-snapshot.h"
     
     #if BUILDFLAG(IS_MAC)
     #include "shell/app/electron_main_delegate_mac.h"
    @@ -207,6 +213,20 @@ void RegisterPathProvider() {
                                           PATH_END);
     }
     
    +void ValidateV8Snapshot(v8::StartupData* data) {
    +  if (data->data &&
    +      electron::fuses::IsEmbeddedAsarIntegrityValidationEnabled()) {
    +    CHECK_GT(data->raw_size, 0);
    +    UNSAFE_BUFFERS({
    +      base::span<const char> span_data(
    +          data->data, static_cast<unsigned long>(data->raw_size));
    +      CHECK(base::ToLowerASCII(base::HexEncode(
    +                crypto::hash::Sha256(base::as_bytes(span_data)))) ==
    +            electron::snapshot_checksum::kChecksum);
    +    })
    +  }
    +}
    +
     }  // namespace
     
     std::string LoadResourceBundle(const std::string& locale) {
    @@ -230,7 +250,9 @@ std::string LoadResourceBundle(const std::string& locale) {
       return loaded_locale;
     }
     
    -ElectronMainDelegate::ElectronMainDelegate() = default;
    +ElectronMainDelegate::ElectronMainDelegate() {
    +  gin::SetV8SnapshotValidator(base::BindRepeating(&ValidateV8Snapshot));
    +}
     
     ElectronMainDelegate::~ElectronMainDelegate() = default;
     
    
fdf29ce83870

fix: ensure snapshot is valid (#48101)

https://github.com/electron/electronSamuel AttardAug 18, 2025via ghsa
5 files changed · +144 1
  • build/checksum_header.py+37 0 added
    @@ -0,0 +1,37 @@
    +#!/usr/bin/env python3
    +
    +import os
    +import sys
    +import hashlib
    +
    +dir_path = os.path.dirname(os.path.realpath(__file__))
    +
    +TEMPLATE_H = """
    +#ifndef ELECTRON_SNAPSHOT_CHECKSUM_H_
    +#define ELECTRON_SNAPSHOT_CHECKSUM_H_
    +
    +namespace electron::snapshot_checksum {
    +
    +const std::string kChecksum = "{checksum}";
    +
    +}  // namespace electron::snapshot_checksum
    +
    +#endif  // ELECTRON_SNAPSHOT_CHECKSUM_H_
    +"""
    +
    +def calculate_sha256(filepath):
    +    sha256_hash = hashlib.sha256()
    +    with open(filepath, "rb") as f:
    +        for byte_block in iter(lambda: f.read(4096), b""):
    +            sha256_hash.update(byte_block)
    +    return sha256_hash.hexdigest()
    +
    +input_file = sys.argv[1]
    +output_file = sys.argv[2]
    +
    +checksum = calculate_sha256(input_file)
    +
    +checksum_h = TEMPLATE_H.replace("{checksum}", checksum)
    +
    +with open(output_file, 'w') as f:
    +    f.write(checksum_h)
    
  • BUILD.gn+16 0 modified
    @@ -518,6 +518,10 @@ source_set("electron_lib") {
         "//v8:v8_libplatform",
       ]
     
    +  if (v8_use_external_startup_data && use_v8_context_snapshot) {
    +    deps += [ ":mksnapshot_checksum_gen" ]
    +  }
    +
       public_deps = [
         "//base",
         "//base:i18n",
    @@ -772,6 +776,18 @@ source_set("electron_lib") {
       }
     }
     
    +action("mksnapshot_checksum_gen") {
    +  script = "build/checksum_header.py"
    +
    +  outputs = [ "$target_gen_dir/snapshot_checksum.h" ]
    +  inputs = [ "$root_out_dir/$v8_context_snapshot_filename" ]
    +  args = rebase_path(inputs)
    +
    +  args += rebase_path(outputs)
    +
    +  deps = [ "//tools/v8_context_snapshot" ]
    +}
    +
     electron_paks("packed_resources") {
       if (is_mac) {
         output_dir = "$root_gen_dir/electron_repack"
    
  • patches/chromium/feat_add_support_for_embedder_snapshot_validation.patch+67 0 added
    @@ -0,0 +1,67 @@
    +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
    +From: Samuel Attard <sattard@anthropic.com>
    +Date: Fri, 15 Aug 2025 14:58:12 -0700
    +Subject: feat: add support for embedder snapshot validation
    +
    +IsValid is not exposed despite being commented as for embedders, this exposes something that works for us.
    +
    +diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc
    +index 1abeb30142251c7abea1b33f7921f79d85532475..758022b4ca4c5cb69ff3df0399194dfca5c1b432 100644
    +--- a/gin/v8_initializer.cc
    ++++ b/gin/v8_initializer.cc
    +@@ -76,11 +76,23 @@ bool GenerateEntropy(unsigned char* buffer, size_t amount) {
    +   return true;
    + }
    + 
    ++static base::RepeatingCallback<void(v8::StartupData*)>& SnapshotValidator() {
    ++  static base::NoDestructor<base::RepeatingCallback<void(v8::StartupData*)>>
    ++      validator(
    ++          base::BindRepeating([](v8::StartupData* data) -> void { /* empty */ }));
    ++  return *validator;
    ++}
    ++
    ++void SetV8SnapshotValidatorInner(const base::RepeatingCallback<void(v8::StartupData*)>& callback) {
    ++  SnapshotValidator() = std::move(callback);
    ++}
    ++
    + void GetMappedFileData(base::MemoryMappedFile* mapped_file,
    +                        v8::StartupData* data) {
    +   if (mapped_file) {
    +     data->data = reinterpret_cast<const char*>(mapped_file->data());
    +     data->raw_size = static_cast<int>(mapped_file->length());
    ++    SnapshotValidator().Run(data);
    +   } else {
    +     data->data = nullptr;
    +     data->raw_size = 0;
    +@@ -225,6 +237,10 @@ constexpr std::string_view kV8FlagParam = "V8FlagParam";
    + 
    + }  // namespace
    + 
    ++void SetV8SnapshotValidator(const base::RepeatingCallback<void(v8::StartupData*)>& callback) {
    ++  SetV8SnapshotValidatorInner(std::move(callback));
    ++}
    ++
    + class V8FeatureVisitor : public base::FeatureVisitor {
    +  public:
    +   void Visit(const std::string& feature_name,
    +diff --git a/gin/v8_initializer.h b/gin/v8_initializer.h
    +index 6f7382cd600cd34916d9382878aee4b469dae5d0..61ed0f46437d2e1abbcebcfb64df06d17c8d9139 100644
    +--- a/gin/v8_initializer.h
    ++++ b/gin/v8_initializer.h
    +@@ -11,6 +11,7 @@
    + 
    + #include "base/files/file.h"
    + #include "base/files/memory_mapped_file.h"
    ++#include "base/functional/callback.h"
    + #include "build/build_config.h"
    + #include "gin/array_buffer.h"
    + #include "gin/gin_export.h"
    +@@ -28,6 +29,8 @@ class StartupData;
    + 
    + namespace gin {
    + 
    ++void SetV8SnapshotValidator(const base::RepeatingCallback<void(v8::StartupData*)>& callback);
    ++
    + class GIN_EXPORT V8Initializer {
    +  public:
    +   // This should be called by IsolateHolder::Initialize().
    
  • patches/chromium/.patches+1 0 modified
    @@ -137,3 +137,4 @@ build_set_mac_sdk_minimum_to_10.patch
     fix_add_macos_memory_query_fallback_to_avoid_crash.patch
     fix_resolve_dynamic_background_material_update_issue_on_windows_11.patch
     chore_restore_some_deprecated_wrapper_utility_in_gin.patch
    +feat_add_support_for_embedder_snapshot_validation.patch
    
  • shell/app/electron_main_delegate.cc+23 1 modified
    @@ -19,15 +19,20 @@
     #include "base/logging.h"
     #include "base/path_service.h"
     #include "base/strings/cstring_view.h"
    +#include "base/strings/string_number_conversions.cc"
    +#include "base/strings/string_util_internal.h"
     #include "chrome/common/chrome_paths.h"
     #include "chrome/common/chrome_switches.h"
     #include "components/content_settings/core/common/content_settings_pattern.h"
     #include "content/public/app/initialize_mojo_core.h"
     #include "content/public/common/content_switches.h"
    +#include "crypto/hash.h"
     #include "electron/buildflags/buildflags.h"
     #include "electron/fuses.h"
     #include "electron/mas.h"
    +#include "electron/snapshot_checksum.h"
     #include "extensions/common/constants.h"
    +#include "gin/v8_initializer.h"
     #include "sandbox/policy/switches.h"
     #include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
     #include "shell/app/command_line_args.h"
    @@ -49,6 +54,7 @@
     #include "third_party/abseil-cpp/absl/types/variant.h"
     #include "ui/base/resource/resource_bundle.h"
     #include "ui/base/ui_base_switches.h"
    +#include "v8/include/v8-snapshot.h"
     
     #if BUILDFLAG(IS_MAC)
     #include "shell/app/electron_main_delegate_mac.h"
    @@ -207,6 +213,20 @@ void RegisterPathProvider() {
                                           PATH_END);
     }
     
    +void ValidateV8Snapshot(v8::StartupData* data) {
    +  if (data->data &&
    +      electron::fuses::IsEmbeddedAsarIntegrityValidationEnabled()) {
    +    CHECK_GT(data->raw_size, 0);
    +    UNSAFE_BUFFERS({
    +      base::span<const char> span_data(
    +          data->data, static_cast<unsigned long>(data->raw_size));
    +      CHECK(base::ToLowerASCII(base::HexEncode(
    +                crypto::hash::Sha256(base::as_bytes(span_data)))) ==
    +            electron::snapshot_checksum::kChecksum);
    +    })
    +  }
    +}
    +
     }  // namespace
     
     std::string LoadResourceBundle(const std::string& locale) {
    @@ -230,7 +250,9 @@ std::string LoadResourceBundle(const std::string& locale) {
       return loaded_locale;
     }
     
    -ElectronMainDelegate::ElectronMainDelegate() = default;
    +ElectronMainDelegate::ElectronMainDelegate() {
    +  gin::SetV8SnapshotValidator(base::BindRepeating(&ValidateV8Snapshot));
    +}
     
     ElectronMainDelegate::~ElectronMainDelegate() = default;
     
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

11

News mentions

0

No linked articles in our index yet.