Description: Check workspace bounds before case conversion writes (VSV00020)
Author: Walid Boudebouda <walid.boudebouda@gmail.com>
Origin: https://code.vinyl-cache.org/vinyl-cache/vinyl-cache/commit/853d397f30753bce1587991fcf9193c63fb4d1eb
Bug: https://vinyl-cache.org/security/VSV00020.html
Forwarded: not-needed
Last-Update: 2026-10-23
 .
 Backport to 7.7 by adapting bin/vinyld to bin/varnishd. Retain the
 stable AN(s) check.

Index: varnish-7.7.0/bin/varnishd/cache/cache_vrt.c
===================================================================
--- varnish-7.7.0.orig/bin/varnishd/cache/cache_vrt.c
+++ varnish-7.7.0/bin/varnishd/cache/cache_vrt.c
@@ -497,7 +497,7 @@ VRT_UpperLowerStrands(VRT_CTX, VCL_STRAN
 	unsigned u;
 	char *b, *e, *r;
 	const char *p, *q = NULL;
-	int i, copy = 0;
+	int i, copy = 0, op = 0;
 
 	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
 	CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
@@ -511,15 +511,20 @@ VRT_UpperLowerStrands(VRT_CTX, VCL_STRAN
 		if (q != NULL)
 			copy = 1;
 		for(p = q = s->p[i]; *p != '\0'; p++) {
-			if ((up && vct_islower(*p)) ||
-			    (!up && vct_isupper(*p))) {
-				*b++ = *p ^ 0x20;
+			op = up ? vct_islower(*p) : vct_isupper(*p);
+
+			if (op)
 				copy = 1;
-			} else if (b < e) {
-				*b++ = *p;
-			}
-			if (copy && b == e)
+
+			if (!copy && b == e)
+				continue;
+			else if (b == e)
 				break;
+
+			if (op)
+				*b++ = *p ^ 0x20;
+			else
+				*b++ = *p;
 		}
 		if (copy && b == e) {
 			WS_Release(ctx->ws, 0);
