[php-src] master: Throw an error on null byte in curl array options (#22662)

Sjoerd Langkemper via GitHub <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Sjoerd Langkemper (Sjord)
Committer: GitHub (web-flow)
Pusher: Girgias
Date: 2026-07-10T13:37:32+01:00

Commit: https://github.com/php/php-src/commit/d1d144e44bd3a23c7f80c6d29dd77d4d43e089a0
Raw diff: https://github.com/php/php-src/commit/d1d144e44bd3a23c7f80c6d29dd77d4d43e089a0.diff

Throw an error on null byte in curl array options (#22662)

This is already done for string options in php_curl_option_str
(see bug #68089). Similarly, array arguments should also not contain
null bytes, so we throw the same error for these.

This was extracted from https://github.com/php/php-src/pull/22651, as
this seems less controversial.

Using null bytes is clearly not supported and curl just throws away
everything after the null byte, so
https://wiki.php.net/rfc/policy-exempt-type-value-error-bc-policy seems
to apply here.

Changed paths:
  A  ext/curl/tests/curl_setopt_error_nul_byte.phpt
  M  ext/curl/interface.c


Diff:

diff --git a/ext/curl/interface.c b/ext/curl/interface.c
index 1dff14b7c8c2..09c7009068b6 100644
--- a/ext/curl/interface.c
+++ b/ext/curl/interface.c
@@ -2030,42 +2030,42 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
 			HashTable *ph;
 			zend_string *val, *tmp_val;
 			struct curl_slist *slist = NULL;
+			const char *name = NULL;
 
-			if (Z_TYPE_P(zvalue) != IS_ARRAY) {
-				const char *name = NULL;
-				switch (option) {
-					case CURLOPT_HTTPHEADER:
-						name = "CURLOPT_HTTPHEADER";
-						break;
-					case CURLOPT_QUOTE:
-						name = "CURLOPT_QUOTE";
-						break;
-					case CURLOPT_HTTP200ALIASES:
-						name = "CURLOPT_HTTP200ALIASES";
-						break;
-					case CURLOPT_POSTQUOTE:
-						name = "CURLOPT_POSTQUOTE";
-						break;
-					case CURLOPT_PREQUOTE:
-						name = "CURLOPT_PREQUOTE";
-						break;
-					case CURLOPT_TELNETOPTIONS:
-						name = "CURLOPT_TELNETOPTIONS";
-						break;
-					case CURLOPT_MAIL_RCPT:
-						name = "CURLOPT_MAIL_RCPT";
-						break;
-					case CURLOPT_RESOLVE:
-						name = "CURLOPT_RESOLVE";
-						break;
-					case CURLOPT_PROXYHEADER:
-						name = "CURLOPT_PROXYHEADER";
-						break;
-					case CURLOPT_CONNECT_TO:
-						name = "CURLOPT_CONNECT_TO";
-						break;
-				}
+			switch (option) {
+				case CURLOPT_HTTPHEADER:
+					name = "CURLOPT_HTTPHEADER";
+					break;
+				case CURLOPT_QUOTE:
+					name = "CURLOPT_QUOTE";
+					break;
+				case CURLOPT_HTTP200ALIASES:
+					name = "CURLOPT_HTTP200ALIASES";
+					break;
+				case CURLOPT_POSTQUOTE:
+					name = "CURLOPT_POSTQUOTE";
+					break;
+				case CURLOPT_PREQUOTE:
+					name = "CURLOPT_PREQUOTE";
+					break;
+				case CURLOPT_TELNETOPTIONS:
+					name = "CURLOPT_TELNETOPTIONS";
+					break;
+				case CURLOPT_MAIL_RCPT:
+					name = "CURLOPT_MAIL_RCPT";
+					break;
+				case CURLOPT_RESOLVE:
+					name = "CURLOPT_RESOLVE";
+					break;
+				case CURLOPT_PROXYHEADER:
+					name = "CURLOPT_PROXYHEADER";
+					break;
+				case CURLOPT_CONNECT_TO:
+					name = "CURLOPT_CONNECT_TO";
+					break;
+			}
 
+			if (Z_TYPE_P(zvalue) != IS_ARRAY) {
 				zend_type_error("%s(): The %s option must have an array value", get_active_function_name(), name);
 				return FAILURE;
 			}
@@ -2074,6 +2074,14 @@ static zend_result _php_curl_setopt(php_curl *ch, zend_long option, zval *zvalue
 			ZEND_HASH_FOREACH_VAL(ph, current) {
 				ZVAL_DEREF(current);
 				val = zval_get_tmp_string(current, &tmp_val);
+
+				if (zend_str_has_nul_byte(val)) {
+					curl_slist_free_all(slist);
+					zend_tmp_string_release(tmp_val);
+					zend_value_error("%s(): cURL option %s must not contain any null bytes", get_active_function_name(), name);
+					return FAILURE;
+				}
+
 				struct curl_slist *new_slist = curl_slist_append(slist, ZSTR_VAL(val));
 				zend_tmp_string_release(tmp_val);
 				if (!new_slist) {
diff --git a/ext/curl/tests/curl_setopt_error_nul_byte.phpt b/ext/curl/tests/curl_setopt_error_nul_byte.phpt
new file mode 100644
index 000000000000..23be973b82c2
--- /dev/null
+++ b/ext/curl/tests/curl_setopt_error_nul_byte.phpt
@@ -0,0 +1,52 @@
+--TEST--
+curl_setopt() throws ValueError for NUL bytes in lists
+--EXTENSIONS--
+curl
+--FILE--
+<?php
+
+$ch = curl_init();
+
+$list_options = [
+    "CURLOPT_HTTP200ALIASES",
+    "CURLOPT_HTTPHEADER",
+    "CURLOPT_POSTQUOTE",
+    "CURLOPT_PREQUOTE",
+    "CURLOPT_QUOTE",
+    "CURLOPT_TELNETOPTIONS",
+    "CURLOPT_MAIL_RCPT",
+    "CURLOPT_RESOLVE",
+    "CURLOPT_PROXYHEADER",
+    "CURLOPT_CONNECT_TO",
+];
+
+foreach ($list_options as $option) {
+    try {
+        curl_setopt($ch, constant($option), ["Something: foo\0bar"]);
+    } catch (ValueError $exception) {
+        echo $option . ": " . $exception->getMessage() . "\n\n";
+    }
+}
+
+$ch = null;
+?>
+--EXPECT--
+CURLOPT_HTTP200ALIASES: curl_setopt(): cURL option CURLOPT_HTTP200ALIASES must not contain any null bytes
+
+CURLOPT_HTTPHEADER: curl_setopt(): cURL option CURLOPT_HTTPHEADER must not contain any null bytes
+
+CURLOPT_POSTQUOTE: curl_setopt(): cURL option CURLOPT_POSTQUOTE must not contain any null bytes
+
+CURLOPT_PREQUOTE: curl_setopt(): cURL option CURLOPT_PREQUOTE must not contain any null bytes
+
+CURLOPT_QUOTE: curl_setopt(): cURL option CURLOPT_QUOTE must not contain any null bytes
+
+CURLOPT_TELNETOPTIONS: curl_setopt(): cURL option CURLOPT_TELNETOPTIONS must not contain any null bytes
+
+CURLOPT_MAIL_RCPT: curl_setopt(): cURL option CURLOPT_MAIL_RCPT must not contain any null bytes
+
+CURLOPT_RESOLVE: curl_setopt(): cURL option CURLOPT_RESOLVE must not contain any null bytes
+
+CURLOPT_PROXYHEADER: curl_setopt(): cURL option CURLOPT_PROXYHEADER must not contain any null bytes
+
+CURLOPT_CONNECT_TO: curl_setopt(): cURL option CURLOPT_CONNECT_TO must not contain any null bytes
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.