From e5587d89796b51a8226fb00a225b1006e406f659 Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Wed, 15 Jul 2026 16:11:30 -1000 Subject: Check `max-blob-size` before reading, default 10 MB Only the tree view honoured the limit, and only after loading the whole object. The raw blob, plain, blame and readme paths now check the size before reading, and the default moves from unlimited to 10 MB so a fresh install never buffers a huge object whole, with zero still the opt-out. --- cgitrc.5.txt | 6 ++++-- source/cgit.c | 2 +- source/ui-blame.c | 6 ++++++ source/ui-blob.c | 10 ++++++++++ source/ui-plain.c | 8 ++++++++ source/ui-tree.c | 15 ++++++++------- 6 files changed, 37 insertions(+), 10 deletions(-) diff --git a/cgitrc.5.txt b/cgitrc.5.txt index b5315cc..b15505f 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -283,8 +283,10 @@ max-atom-items:: value: "10". max-blob-size:: - Specifies the maximum size of a blob to display HTML for in KBytes. - Default value: "0" (limit disabled). + Specifies the maximum size in KBytes of a blob that cgit will read into + memory to serve. It caps both the HTML blob view and the raw "plain" and + "blob" output, and a larger object is refused rather than loaded whole. + Default value: "10240" (10 MB). Set to "0" to disable the limit. max-commit-count:: Specifies the number of entries to list per page in "log" view. Default diff --git a/source/cgit.c b/source/cgit.c index 8a7027c..d80aebd 100644 --- a/source/cgit.c +++ b/source/cgit.c @@ -403,7 +403,7 @@ static void prepare_context(void) ctx.cfg.max_lock_attempts = 5; ctx.cfg.max_msg_len = 80; ctx.cfg.max_repodesc_len = 80; - ctx.cfg.max_blob_size = 0; + ctx.cfg.max_blob_size = 10 * 1024; /* 10 MB; bounds per-request memory */ ctx.cfg.max_stats = 0; ctx.cfg.project_list = NULL; ctx.cfg.renamelimit = -1; diff --git a/source/ui-blame.c b/source/ui-blame.c index 1b9df88..99f6de0 100644 --- a/source/ui-blame.c +++ b/source/ui-blame.c @@ -127,6 +127,12 @@ static void print_object(const struct object_id *oid, const char *path, oid_to_hex(oid)); return; } + if (ctx.cfg.max_blob_size && size / 1024 > (unsigned long)ctx.cfg.max_blob_size) { + cgit_print_error_page(413, "Too large", + "blob size (%luKB) exceeds display size limit (%dKB)", + size / 1024, ctx.cfg.max_blob_size); + return; + } buf = odb_read_object(the_repository->objects, oid, &type, &size); if (!buf) { diff --git a/source/ui-blob.c b/source/ui-blob.c index ad84f3d..67c718b 100644 --- a/source/ui-blob.c +++ b/source/ui-blob.c @@ -102,6 +102,8 @@ int cgit_print_file(char *path, const char *head, int file_only, int html_escape } if (type == OBJ_BAD) return -1; + if (ctx.cfg.max_blob_size && size / 1024 > (unsigned long)ctx.cfg.max_blob_size) + return -1; buf = odb_read_object(the_repository->objects, &oid, &type, &size); if (!buf) return -1; @@ -170,6 +172,14 @@ void cgit_print_blob(const char *hex, char *path, const char *head, int file_onl return; } + /* Reject an oversized object before reading it whole into memory. */ + if (ctx.cfg.max_blob_size && size / 1024 > (unsigned long)ctx.cfg.max_blob_size) { + cgit_print_error_page(413, "Too large", + "Object size (%luKB) exceeds limit (%dKB)", + size / 1024, ctx.cfg.max_blob_size); + return; + } + buf = odb_read_object(the_repository->objects, &oid, &type, &size); if (!buf) { cgit_print_error_page(500, "Internal server error", diff --git a/source/ui-plain.c b/source/ui-plain.c index c041711..8486fa4 100644 --- a/source/ui-plain.c +++ b/source/ui-plain.c @@ -30,6 +30,14 @@ static int print_object(const struct object_id *oid, const char *path) return 1; } + /* Reject an oversized object before reading it whole into memory. */ + if (ctx.cfg.max_blob_size && size / 1024 > (unsigned long)ctx.cfg.max_blob_size) { + cgit_print_error_page(413, "Too large", + "Object size (%luKB) exceeds limit (%dKB)", + size / 1024, ctx.cfg.max_blob_size); + return 1; + } + buf = odb_read_object(the_repository->objects, oid, &type, &size); if (!buf) { cgit_print_error_page(404, "Not found", "Not found"); diff --git a/source/ui-tree.c b/source/ui-tree.c index 292bfc6..f820f1f 100644 --- a/source/ui-tree.c +++ b/source/ui-tree.c @@ -117,6 +117,14 @@ static int print_object(const struct object_id *oid, const char *path, const cha return 0; } + /* Reject an oversized object before reading it whole into memory. */ + if (ctx.cfg.max_blob_size && size / 1024 > (unsigned long)ctx.cfg.max_blob_size) { + cgit_print_error_page(413, "Too large", + "blob size (%luKB) exceeds display size limit (%dKB)", + size / 1024, ctx.cfg.max_blob_size); + return 0; + } + buf = odb_read_object(the_repository->objects, oid, &type, &size); if (!buf) { cgit_print_error_page(500, "Internal server error", @@ -138,13 +146,6 @@ static int print_object(const struct object_id *oid, const char *path, const cha } html(")\n"); - if (ctx.cfg.max_blob_size && size / 1024 > ctx.cfg.max_blob_size) { - htmlf("
blob size (%ldKB) exceeds display size limit (%dKB).
", - size / 1024, ctx.cfg.max_blob_size); - free(buf); - return 1; - } - if (is_binary) print_binary_buffer(buf, size); else -- cgit v2.8.0