diff --git a/courgette/disassembler_win32.cc b/courgette/disassembler_win32.cc
index b89db4507425c..1592c219f8a86 100644
--- a/courgette/disassembler_win32.cc
+++ b/courgette/disassembler_win32.cc
@@ -67,7 +67,7 @@ FileOffset DisassemblerWin32::RVAToFileOffset(RVA rva) const {
 // structure.
 //
 bool DisassemblerWin32::ParseHeader() {
-  if (length() < kOffsetOfFileAddressOfNewExeHeader + 4 /*size*/)
+  if (!IsRangeInBounds(kOffsetOfFileAddressOfNewExeHeader, 4))
     return Bad("Too small");
 
   // Have 'MZ' magic for a DOS header?
@@ -75,100 +75,98 @@ bool DisassemblerWin32::ParseHeader() {
     return Bad("Not MZ");
 
   // offset from DOS header to PE header is stored in DOS header.
-  FileOffset file_offset = static_cast<FileOffset>(
+  FileOffset pe_header_offset = static_cast<FileOffset>(
       ReadU32(start(), kOffsetOfFileAddressOfNewExeHeader));
-
-  if (file_offset >= length())
-    return Bad("Bad offset to PE header");
-
-  const uint8_t* const pe_header = FileOffsetToPointer(file_offset);
-  const size_t kMinPEHeaderSize = 4 /*signature*/ + kSizeOfCoffHeader;
-  if (pe_header <= start() || pe_header >= end() - kMinPEHeaderSize)
-    return Bad("Bad file offset to PE header");
-
-  if (file_offset % 8 != 0)
+  if (pe_header_offset % 8 != 0)
     return Bad("Misaligned PE header");
+  if (pe_header_offset < kOffsetOfFileAddressOfNewExeHeader + 4)
+    return Bad("PE header pathological overlap");
+  if (!IsRangeInBounds(pe_header_offset, kMinPeHeaderSize))
+    return Bad("PE header past end of file");
+
+  const uint8_t* const pe_header = FileOffsetToPointer(pe_header_offset);
 
   // The 'PE' header is an IMAGE_NT_HEADERS structure as defined in WINNT.H.
   // See http://msdn.microsoft.com/en-us/library/ms680336(VS.85).aspx
   //
   // The first field of the IMAGE_NT_HEADERS is the signature.
   if (!(pe_header[0] == 'P' && pe_header[1] == 'E' && pe_header[2] == 0 &&
-        pe_header[3] == 0))
+        pe_header[3] == 0)) {
     return Bad("No PE signature");
+  }
 
   // The second field of the IMAGE_NT_HEADERS is the COFF header.
   // The COFF header is also called an IMAGE_FILE_HEADER
   //   http://msdn.microsoft.com/en-us/library/ms680313(VS.85).aspx
-  const uint8_t* const coff_header = pe_header + 4;
+  FileOffset coff_header_offset = pe_header_offset + 4;
+  if (!IsRangeInBounds(coff_header_offset, kSizeOfCoffHeader))
+    return Bad("COFF header past end of file");
+  const uint8_t* const coff_header = start() + coff_header_offset;
   machine_type_ = ReadU16(coff_header, 0);
   number_of_sections_ = ReadU16(coff_header, 2);
   size_of_optional_header_ = ReadU16(coff_header, 16);
-
-  // The rest of the IMAGE_NT_HEADERS is the IMAGE_OPTIONAL_HEADER(32|64)
-  const uint8_t* const optional_header = coff_header + kSizeOfCoffHeader;
-  optional_header_ = optional_header;
-
-  if (optional_header + size_of_optional_header_ >= end())
-    return Bad("Optional header past end of file");
-
   // Check we can read the magic.
   if (size_of_optional_header_ < 2)
     return Bad("Optional header no magic");
+  // Check that we can read the rest of the the fixed fields. Data directories
+  // directly follow the fixed fields of the IMAGE_OPTIONAL_HEADER.
+  if (size_of_optional_header_ < RelativeOffsetOfDataDirectories())
+    return Bad("Optional header too short");
 
-  uint16_t magic = ReadU16(optional_header, 0);
+  // The rest of the IMAGE_NT_HEADERS is the IMAGE_OPTIONAL_HEADER(32|64)
+  FileOffset optional_header_offset = pe_header_offset + kMinPeHeaderSize;
+  if (!IsRangeInBounds(optional_header_offset, size_of_optional_header_))
+    return Bad("Optional header past end of file");
+  optional_header_ = start() + optional_header_offset;
 
+  uint16_t magic = ReadU16(optional_header_, 0);
   switch (kind()) {
     case EXE_WIN_32_X86:
-      if (magic != kImageNtOptionalHdr32Magic) {
+      if (magic != kImageNtOptionalHdr32Magic)
         return Bad("64 bit executables are not supported by this disassembler");
-      }
       break;
 
     case EXE_WIN_32_X64:
-      if (magic != kImageNtOptionalHdr64Magic) {
+      if (magic != kImageNtOptionalHdr64Magic)
         return Bad("32 bit executables are not supported by this disassembler");
-      }
       break;
 
     default:
       return Bad("Unrecognized magic");
   }
 
-  // Check that we can read the rest of the the fixed fields.  Data directories
-  // directly follow the fixed fields of the IMAGE_OPTIONAL_HEADER.
-  if (size_of_optional_header_ < OffsetOfDataDirectories())
-    return Bad("Optional header too short");
-
   // The optional header is either an IMAGE_OPTIONAL_HEADER32 or
   // IMAGE_OPTIONAL_HEADER64
   // http://msdn.microsoft.com/en-us/library/ms680339(VS.85).aspx
   //
   // Copy the fields we care about.
-  size_of_code_ = ReadU32(optional_header, 4);
-  size_of_initialized_data_ = ReadU32(optional_header, 8);
-  size_of_uninitialized_data_ = ReadU32(optional_header, 12);
-  base_of_code_ = ReadU32(optional_header, 20);
+  size_of_code_ = ReadU32(optional_header_, 4);
+  size_of_initialized_data_ = ReadU32(optional_header_, 8);
+  size_of_uninitialized_data_ = ReadU32(optional_header_, 12);
+  base_of_code_ = ReadU32(optional_header_, 20);
 
   switch (kind()) {
     case EXE_WIN_32_X86:
-      base_of_data_ = ReadU32(optional_header, 24);
-      image_base_ = ReadU32(optional_header, 28);
-      size_of_image_ = ReadU32(optional_header, 56);
-      number_of_data_directories_ = ReadU32(optional_header, 92);
+      base_of_data_ = ReadU32(optional_header_, 24);
+      image_base_ = ReadU32(optional_header_, 28);
+      size_of_image_ = ReadU32(optional_header_, 56);
+      number_of_data_directories_ = ReadU32(optional_header_, 92);
       break;
 
     case EXE_WIN_32_X64:
       base_of_data_ = 0;
-      image_base_ = ReadU64(optional_header, 24);
-      size_of_image_ = ReadU32(optional_header, 56);
-      number_of_data_directories_ = ReadU32(optional_header, 108);
+      image_base_ = ReadU64(optional_header_, 24);
+      size_of_image_ = ReadU32(optional_header_, 56);
+      number_of_data_directories_ = ReadU32(optional_header_, 108);
       break;
 
     default:
       NOTREACHED();
   }
 
+  if (size_of_image_ >= 0x80000000U)
+    return Bad("Invalid SizeOfImage");
+
   if (size_of_code_ >= length() || size_of_initialized_data_ >= length() ||
       size_of_code_ + size_of_initialized_data_ >= length()) {
     // This validation fires on some perfectly fine executables.
@@ -188,15 +186,19 @@ bool DisassemblerWin32::ParseHeader() {
   b &= ReadDataDirectory(12, &import_address_table_);
   b &= ReadDataDirectory(13, &delay_import_descriptor_);
   b &= ReadDataDirectory(14, &clr_runtime_header_);
-  if (!b) {
+  if (!b)
     return Bad("Malformed data directory");
-  }
 
   // Sections follow the optional header.
-  sections_ = reinterpret_cast<const Section*>(optional_header +
-                                               size_of_optional_header_);
-  size_t detected_length = 0;
+  FileOffset sections_offset =
+      optional_header_offset + size_of_optional_header_;
+  if (!IsArrayInBounds(sections_offset, number_of_sections_, sizeof(Section)))
+    return Bad("Sections past end of file");
+  sections_ = reinterpret_cast<const Section*>(start() + sections_offset);
+  if (!CheckSectionRanges())
+    return Bad("Out of bound section");
 
+  size_t detected_length = 0;
   for (int i = 0; i < number_of_sections_; ++i) {
     const Section* section = &sections_[i];
 
@@ -318,29 +320,47 @@ std::string DisassemblerWin32::SectionName(const Section* section) {
 bool DisassemblerWin32::QuickDetect(const uint8_t* start,
                                     size_t length,
                                     uint16_t magic) {
-  if (length < kOffsetOfFileAddressOfNewExeHeader + 4 /* size */)
+  if (length < kOffsetOfFileAddressOfNewExeHeader + 4)
     return false;
 
   // Have 'MZ' magic for a DOS header?
   if (start[0] != 'M' || start[1] != 'Z')
     return false;
 
-  FileOffset file_offset = static_cast<FileOffset>(
+  FileOffset pe_header_offset = static_cast<FileOffset>(
       ReadU32(start, kOffsetOfFileAddressOfNewExeHeader));
-  if (file_offset >= length || file_offset % 8 != 0)
+  if (pe_header_offset % 8 != 0 ||
+      pe_header_offset < kOffsetOfFileAddressOfNewExeHeader + 4 ||
+      pe_header_offset >= length ||
+      length - pe_header_offset < kMinPeHeaderSize) {
     return false;
-  const uint8_t* const pe_header = start + file_offset;
-  const size_t kMinPEHeaderSize = 4 /*signature*/ + kSizeOfCoffHeader;
-  if (pe_header <= start || pe_header + kMinPEHeaderSize >= start + length)
+  }
+  const uint8_t* pe_header = start + pe_header_offset;
+  if (!(pe_header[0] == 'P' && pe_header[1] == 'E' && pe_header[2] == 0 &&
+        pe_header[3] == 0)) {
     return false;
+  }
 
-  const uint8_t* optional_header = pe_header + 4 + kSizeOfCoffHeader;
-  // Check we can read the magic.
-  if (optional_header + 2 >= start + length)
-    return false;
-  if (magic != ReadU16(optional_header, 0))
+  FileOffset optional_header_offset = pe_header_offset + kMinPeHeaderSize;
+  if (optional_header_offset >= length || length - optional_header_offset < 2)
     return false;
+  const uint8_t* optional_header = start + optional_header_offset;
+  return magic == ReadU16(optional_header, 0);
+}
 
+bool DisassemblerWin32::IsRvaRangeInBounds(size_t start, size_t length) {
+  return start < size_of_image_ && length <= size_of_image_ - start;
+}
+
+bool DisassemblerWin32::CheckSectionRanges() {
+  for (int i = 0; i < number_of_sections_; ++i) {
+    const Section* section = &sections_[i];
+    if (!IsRangeInBounds(section->file_offset_of_raw_data,
+                         section->size_of_raw_data) ||
+        !IsRvaRangeInBounds(section->virtual_address, section->virtual_size)) {
+      return false;
+    }
+  }
   return true;
 }
 
@@ -647,7 +667,7 @@ const Section* DisassemblerWin32::FindNextSection(
 bool DisassemblerWin32::ReadDataDirectory(int index,
                                           ImageDataDirectory* directory) {
   if (index < number_of_data_directories_) {
-    FileOffset file_offset = index * 8 + OffsetOfDataDirectories();
+    FileOffset file_offset = index * 8 + RelativeOffsetOfDataDirectories();
     if (file_offset >= size_of_optional_header_)
       return Bad("Number of data directories inconsistent");
     const uint8_t* data_directory = optional_header_ + file_offset;
diff --git a/courgette/disassembler_win32.h b/courgette/disassembler_win32.h
index d2df58c08df60..da6a16d325531 100644
--- a/courgette/disassembler_win32.h
+++ b/courgette/disassembler_win32.h
@@ -55,8 +55,11 @@ class DisassemblerWin32 : public Disassembler {
   // which will be checked against the detected one.
   static bool QuickDetect(const uint8_t* start, size_t length, uint16_t magic);
 
-  bool ParseAbs32Relocs();
-  void ParseRel32RelocsFromSections();
+  // Returns true if the given RVA range lies within [0, |size_of_image_|).
+  bool IsRvaRangeInBounds(size_t start, size_t length);
+
+  // Returns whether all sections lie within image.
+  bool CheckSectionRanges();
 
   // Disassembler interfaces.
   bool ExtractAbs32Locations() override;
@@ -91,7 +94,7 @@ class DisassemblerWin32 : public Disassembler {
                             InstructionReceptor* receptor) const = 0;
   // Returns true if type is recognized.
   virtual bool SupportsRelTableType(int type) const = 0;
-  virtual uint16_t OffsetOfDataDirectories() const = 0;
+  virtual uint16_t RelativeOffsetOfDataDirectories() const = 0;
 
 #if COURGETTE_HISTOGRAM_TARGETS
   void HistogramTargets(const char* kind, const std::map<RVA, int>& map) const;
@@ -132,6 +135,7 @@ class DisassemblerWin32 : public Disassembler {
   RVA base_of_data_ = 0;
 
   uint64_t image_base_ = 0;  // Range limited to 32 bits for 32 bit executable.
+  // Specifies size of loaded PE in memory, and provides bound on RVA.
   uint32_t size_of_image_ = 0;
   int number_of_data_directories_ = 0;
 
diff --git a/courgette/disassembler_win32_x64.h b/courgette/disassembler_win32_x64.h
index a5e8317262de3..837c7455863a2 100644
--- a/courgette/disassembler_win32_x64.h
+++ b/courgette/disassembler_win32_x64.h
@@ -44,7 +44,7 @@ class DisassemblerWin32X64 : public DisassemblerWin32 {
   bool SupportsRelTableType(int type) const override {
     return type == 10;  // IMAGE_REL_BASED_DIR64
   }
-  uint16_t OffsetOfDataDirectories() const override {
+  uint16_t RelativeOffsetOfDataDirectories() const override {
     return kOffsetOfDataDirectoryFromImageOptionalHeader64;
   }
 
diff --git a/courgette/disassembler_win32_x86.h b/courgette/disassembler_win32_x86.h
index f747ef53e9944..84813e660f905 100644
--- a/courgette/disassembler_win32_x86.h
+++ b/courgette/disassembler_win32_x86.h
@@ -44,7 +44,7 @@ class DisassemblerWin32X86 : public DisassemblerWin32 {
   bool SupportsRelTableType(int type) const override {
     return type == 3;  // IMAGE_REL_BASED_HIGHLOW
   }
-  uint16_t OffsetOfDataDirectories() const override {
+  uint16_t RelativeOffsetOfDataDirectories() const override {
     return kOffsetOfDataDirectoryFromImageOptionalHeader32;
   }
 
diff --git a/courgette/types_win_pe.h b/courgette/types_win_pe.h
index f926b5f65c55e..23aecf886ab3a 100644
--- a/courgette/types_win_pe.h
+++ b/courgette/types_win_pe.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef TYPES_WIN_PE_H_
-#define TYPES_WIN_PE_H_
+#ifndef COURGETTE_TYPES_WIN_PE_H_
+#define COURGETTE_TYPES_WIN_PE_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -58,8 +58,10 @@ const uint16_t kImageNtOptionalHdr32Magic = 0x10b;
 const uint16_t kImageNtOptionalHdr64Magic = 0x20b;
 
 const size_t kSizeOfCoffHeader = 20;
+const size_t kMinPeHeaderSize = 4 /*signature*/ + kSizeOfCoffHeader;
 const size_t kOffsetOfDataDirectoryFromImageOptionalHeader32 = 96;
 const size_t kOffsetOfDataDirectoryFromImageOptionalHeader64 = 112;
 
-}  // namespace
-#endif  // TYPES_WIN_PE_H_
+}  // namespace courgette
+
+#endif  // COURGETTE_TYPES_WIN_PE_H_