diff --git a/libzipfile/centraldir.c b/libzipfile/centraldir.c
index 911e2b98b4c297d00b05479b50e4cd5c4255e2e7..2ce73e8ee252969482119c4d28119daf6d6d5c4b 100644
--- a/libzipfile/centraldir.c
+++ b/libzipfile/centraldir.c
@@ -60,16 +60,20 @@ read_central_dir_values(Zipfile* file, const unsigned char* buf, int len)
     return 0;
 }
 
+static const int kCompressionStored = 0x0;
+static const int kCompressionDeflate = 0x8;
+
 static int
 read_central_directory_entry(Zipfile* file, Zipentry* entry,
                 const unsigned char** buf, ssize_t* len)
 {
     const unsigned char* p;
+    size_t remaining;
+    const unsigned char* bufLimit;
 
     unsigned short  versionMadeBy;
     unsigned short  versionToExtract;
     unsigned short  gpBitFlag;
-    unsigned short  compressionMethod;
     unsigned short  lastModFileTime;
     unsigned short  lastModFileDate;
     unsigned long   crc32;
@@ -84,8 +88,9 @@ read_central_directory_entry(Zipfile* file, Zipentry* entry,
     unsigned int dataOffset;
     unsigned short lfhExtraFieldSize;
 
-
     p = *buf;
+    remaining = *len;
+    bufLimit = file->buf + file->bufsize;
 
     if (*len < ENTRY_LEN) {
         fprintf(stderr, "cde entry not large enough\n");
@@ -115,41 +120,88 @@ read_central_directory_entry(Zipfile* file, Zipentry* entry,
     localHeaderRelOffset = read_le_int(&p[0x2a]);
 
     p += ENTRY_LEN;
+    remaining -= ENTRY_LEN;
 
     // filename
     if (entry->fileNameLength != 0) {
+        if (entry->fileNameLength > remaining) {
+            fprintf(stderr, "cde entry not large enough for file name.\n");
+            return 1;
+        }
+
         entry->fileName = p;
     } else {
-        entry->fileName = NULL;
+        fprintf(stderr, "cde entry does not contain a file name.\n");
+        return 1;
     }
     p += entry->fileNameLength;
+    remaining -= entry->fileNameLength;
 
-    // extra field
+    // extra field, if any
     if (extraFieldLength != 0) {
+        if (extraFieldLength > remaining) {
+            fprintf(stderr, "cde entry not large enough for extra field.\n");
+            return 1;
+        }
+
         extraField = p;
     } else {
         extraField = NULL;
     }
     p += extraFieldLength;
+    remaining -= extraFieldLength;
 
     // comment, if any
     if (fileCommentLength != 0) {
+        if (fileCommentLength > remaining) {
+            fprintf(stderr, "cde entry not large enough for file comment.\n");
+            return 1;
+        }
+
         fileComment = p;
     } else {
         fileComment = NULL;
     }
     p += fileCommentLength;
+    remaining -= fileCommentLength;
 
     *buf = p;
+    *len = remaining;
 
     // the size of the extraField in the central dir is how much data there is,
     // but the one in the local file header also contains some padding.
     p = file->buf + localHeaderRelOffset;
+    if (p >= bufLimit) {
+      fprintf(stderr, "Invalid local header offset for entry.\n");
+      return 1;
+    }
+
     extraFieldLength = read_le_short(&p[0x1c]);
 
     dataOffset = localHeaderRelOffset + LFH_SIZE
         + entry->fileNameLength + extraFieldLength;
     entry->data = file->buf + dataOffset;
+
+    // Sanity check: make sure that the start of the entry data is within
+    // our allocated buffer.
+    if ((entry->data < file->buf) || (entry->data >= bufLimit)) {
+      fprintf(stderr, "Invalid data offset for entry.\n");
+      return 1;
+    }
+
+    // Sanity check: make sure that the end of the entry data is within
+    // our allocated buffer. We need to look at the uncompressedSize for
+    // stored entries and the compressed size for deflated entries.
+    if ((entry->compressionMethod == kCompressionStored) &&
+        (entry->uncompressedSize > (unsigned int) (bufLimit - entry->data))) {
+      fprintf(stderr, "Invalid uncompressed size for stored entry.\n");
+      return 1;
+    }
+    if ((entry->compressionMethod == kCompressionDeflate) &&
+        (entry->compressedSize > (unsigned int) (bufLimit - entry->data))) {
+      fprintf(stderr, "Invalid uncompressed size for deflated entry.\n");
+      return 1;
+    }
 #if 0
     printf("file->buf=%p entry->data=%p dataOffset=%x localHeaderRelOffset=%d "
            "entry->fileNameLength=%d extraFieldLength=%d\n",
diff --git a/libzipfile/test_zipfile.c b/libzipfile/test_zipfile.c
index 1aaa9132d3b711fe6ac05b8af310bdaca20f5ad6..a2f6bc7e5938ddf9382b65b71d2fe3754d64dee3 100644
--- a/libzipfile/test_zipfile.c
+++ b/libzipfile/test_zipfile.c
@@ -75,7 +75,6 @@ main(int argc, char** argv)
             unsize = get_zipentry_size(entry);
             size = unsize * 1.001;
             scratch = malloc(size);
-            printf("scratch=%p\n", scratch);
             err = decompress_zipentry(entry, scratch, size);
             if (err != 0) {
                 fprintf(stderr, "error decompressing file\n");