Commit 3036712be90 for php.net
commit 3036712be90ba605a4a39e44f5d7b6619cd7981f
Author: Jordi Kroon <jkroon@onyourmarks.agency>
Date: Mon Sep 21 07:19:04 2026 -0400
tree: Add #[\SensitiveParameter] to more functions taking secrets (#23782)
* ext/sodium: add SensitiveParameter to missing functions
* ext/phar: add SensitiveParameter to missing functions
* ext/snmp: add SensitiveParameter to missing functions
* ext/sqlite3: add SensitiveParameter to missing functions
* ext/hash: add SensitiveParameter to missing functions
diff --git a/ext/hash/hash.stub.php b/ext/hash/hash.stub.php
index d86fa8d2c7e..b89f290b566 100644
--- a/ext/hash/hash.stub.php
+++ b/ext/hash/hash.stub.php
@@ -83,7 +83,7 @@ function mhash_get_hash_name(int $algo): string|false {}
* @refcount 1
*/
#[\Deprecated(since: '8.1')]
-function mhash_keygen_s2k(int $algo, string $password, string $salt, int $length): string|false {}
+function mhash_keygen_s2k(int $algo, #[\SensitiveParameter] string $password, string $salt, int $length): string|false {}
#[\Deprecated(since: '8.1')]
function mhash_count(): int {}
@@ -92,7 +92,7 @@ function mhash_count(): int {}
* @refcount 1
*/
#[\Deprecated(since: '8.1')]
-function mhash(int $algo, string $data, ?string $key = null): string|false {}
+function mhash(int $algo, string $data, #[\SensitiveParameter] ?string $key = null): string|false {}
#endif
final class HashContext
diff --git a/ext/hash/hash_arginfo.h b/ext/hash/hash_arginfo.h
index bc213d02bfb..98cd952cd12 100644
Binary files a/ext/hash/hash_arginfo.h and b/ext/hash/hash_arginfo.h differ
diff --git a/ext/hash/tests/mhash_sensitive_parameter.phpt b/ext/hash/tests/mhash_sensitive_parameter.phpt
new file mode 100644
index 00000000000..c35a82718fe
--- /dev/null
+++ b/ext/hash/tests/mhash_sensitive_parameter.phpt
@@ -0,0 +1,31 @@
+--TEST--
+Test that the key/password parameters of mhash() and mhash_keygen_s2k() are marked sensitive.
+--SKIPIF--
+<?php if (!function_exists('mhash')) { die('skip mhash compatibility layer not available'); } ?>
+--FILE--
+<?php
+declare(strict_types=1);
+
+try {
+ var_dump(mhash(0, null, 'secret-key'));
+} catch (\Throwable $e) {
+ echo $e, PHP_EOL;
+}
+try {
+ var_dump(mhash_keygen_s2k(0, 'secret-password', 'salt', 0));
+} catch (\Throwable $e) {
+ echo $e, PHP_EOL;
+}
+?>
+--EXPECTF--
+Deprecated: Function mhash() is deprecated since 8.1 in %s on line %d
+TypeError: mhash(): Argument #2 ($data) must be of type string, null given in %s:%d
+Stack trace:
+#0 %s(%d): mhash(0, NULL, Object(SensitiveParameterValue))
+#1 {main}
+
+Deprecated: Function mhash_keygen_s2k() is deprecated since 8.1 in %s on line %d
+ValueError: mhash_keygen_s2k(): Argument #4 ($length) must be a greater than 0 in %s:%d
+Stack trace:
+#0 %s(%d): mhash_keygen_s2k(0, Object(SensitiveParameterValue), 'salt', 0)
+#1 {main}
diff --git a/ext/phar/phar_object.stub.php b/ext/phar/phar_object.stub.php
index ae5bd69c32f..dde2719fb1b 100644
--- a/ext/phar/phar_object.stub.php
+++ b/ext/phar/phar_object.stub.php
@@ -196,7 +196,7 @@ public function setDefaultStub(?string $index = null, ?string $webIndex = null):
public function setMetadata(mixed $metadata): void {}
/** @tentative-return-type */
- public function setSignatureAlgorithm(int $algo, ?string $privateKey = null): void {}
+ public function setSignatureAlgorithm(int $algo, #[\SensitiveParameter] ?string $privateKey = null): void {}
/**
* @param resource|string $stub
@@ -470,7 +470,7 @@ public function setMetadata(mixed $metadata): void {}
* @tentative-return-type
* @implementation-alias Phar::setSignatureAlgorithm
*/
- public function setSignatureAlgorithm(int $algo, ?string $privateKey = null): void {}
+ public function setSignatureAlgorithm(int $algo, #[\SensitiveParameter] ?string $privateKey = null): void {}
/**
* @param resource|string $stub
diff --git a/ext/phar/phar_object_arginfo.h b/ext/phar/phar_object_arginfo.h
index bca9f0112ea..f2ebf5ba6ea 100644
Binary files a/ext/phar/phar_object_arginfo.h and b/ext/phar/phar_object_arginfo.h differ
diff --git a/ext/phar/tests/setsignaturealgo_sensitive_parameter.phpt b/ext/phar/tests/setsignaturealgo_sensitive_parameter.phpt
new file mode 100644
index 00000000000..71c58c08c79
--- /dev/null
+++ b/ext/phar/tests/setsignaturealgo_sensitive_parameter.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Test that the private key parameter of Phar::setSignatureAlgorithm() is marked sensitive.
+--EXTENSIONS--
+phar
+--INI--
+phar.require_hash=0
+phar.readonly=0
+--FILE--
+<?php
+$fname = __DIR__ . '/' . basename(__FILE__, '.php') . '.tar';
+$p = new PharData($fname);
+$p['file1.txt'] = 'hi';
+
+try {
+ $p->setSignatureAlgorithm(-1, 'secret-private-key');
+} catch (\Throwable $e) {
+ echo $e, PHP_EOL;
+}
+?>
+--CLEAN--
+<?php
+unlink(__DIR__ . '/' . basename(__FILE__, '.clean.php') . '.tar');
+?>
+--EXPECTF--
+UnexpectedValueException: Unknown signature algorithm specified in %s:%d
+Stack trace:
+#0 %s(%d): PharData->setSignatureAlgorithm(-1, Object(SensitiveParameterValue))
+#1 {main}
diff --git a/ext/snmp/snmp.stub.php b/ext/snmp/snmp.stub.php
index f68da7e75f1..48199f2a662 100644
--- a/ext/snmp/snmp.stub.php
+++ b/ext/snmp/snmp.stub.php
@@ -115,18 +115,18 @@
*/
const SNMP_COUNTER64 = UNKNOWN;
- function snmpget(string $hostname, string $community, array|string $object_id, int $timeout = -1, int $retries = -1): mixed {}
+ function snmpget(string $hostname, #[\SensitiveParameter] string $community, array|string $object_id, int $timeout = -1, int $retries = -1): mixed {}
- function snmpgetnext(string $hostname, string $community, array|string $object_id, int $timeout = -1, int $retries = -1): mixed {}
+ function snmpgetnext(string $hostname, #[\SensitiveParameter] string $community, array|string $object_id, int $timeout = -1, int $retries = -1): mixed {}
- function snmpwalk(string $hostname, string $community, array|string $object_id, int $timeout = -1, int $retries = -1): array|false {}
+ function snmpwalk(string $hostname, #[\SensitiveParameter] string $community, array|string $object_id, int $timeout = -1, int $retries = -1): array|false {}
- function snmprealwalk(string $hostname, string $community, array|string $object_id, int $timeout = -1, int $retries = -1): array|false {}
+ function snmprealwalk(string $hostname, #[\SensitiveParameter] string $community, array|string $object_id, int $timeout = -1, int $retries = -1): array|false {}
/** @alias snmprealwalk */
- function snmpwalkoid(string $hostname, string $community, array|string $object_id, int $timeout = -1, int $retries = -1): array|false {}
+ function snmpwalkoid(string $hostname, #[\SensitiveParameter] string $community, array|string $object_id, int $timeout = -1, int $retries = -1): array|false {}
- function snmpset(string $hostname, string $community, array|string $object_id, array|string $type, array|string $value, int $timeout = -1, int $retries = -1): bool {}
+ function snmpset(string $hostname, #[\SensitiveParameter] string $community, array|string $object_id, array|string $type, array|string $value, int $timeout = -1, int $retries = -1): bool {}
function snmp_get_quick_print(): bool {}
@@ -145,44 +145,44 @@ function snmp_set_string_output_format(Snmp\StringOutput $format): void {}
/** @alias snmp_set_oid_output_format */
function snmp_set_oid_numeric_print(Snmp\OidOutput|int $format): true {}
- function snmp2_get(string $hostname, string $community, array|string $object_id, int $timeout = -1, int $retries = -1): mixed {}
+ function snmp2_get(string $hostname, #[\SensitiveParameter] string $community, array|string $object_id, int $timeout = -1, int $retries = -1): mixed {}
- function snmp2_getnext(string $hostname, string $community, array|string $object_id, int $timeout = -1, int $retries = -1): mixed {}
+ function snmp2_getnext(string $hostname, #[\SensitiveParameter] string $community, array|string $object_id, int $timeout = -1, int $retries = -1): mixed {}
- function snmp2_walk(string $hostname, string $community, array|string $object_id, int $timeout = -1, int $retries = -1): array|false {}
+ function snmp2_walk(string $hostname, #[\SensitiveParameter] string $community, array|string $object_id, int $timeout = -1, int $retries = -1): array|false {}
- function snmp2_real_walk(string $hostname, string $community, array|string $object_id, int $timeout = -1, int $retries = -1): array|false {}
+ function snmp2_real_walk(string $hostname, #[\SensitiveParameter] string $community, array|string $object_id, int $timeout = -1, int $retries = -1): array|false {}
- function snmp2_set(string $hostname, string $community, array|string $object_id, array|string $type, array|string $value, int $timeout = -1, int $retries = -1): bool {}
+ function snmp2_set(string $hostname, #[\SensitiveParameter] string $community, array|string $object_id, array|string $type, array|string $value, int $timeout = -1, int $retries = -1): bool {}
function snmp3_get(
string $hostname, string $security_name, string $security_level,
- string $auth_protocol, string $auth_passphrase,
- string $privacy_protocol, string $privacy_passphrase,
+ string $auth_protocol, #[\SensitiveParameter] string $auth_passphrase,
+ string $privacy_protocol, #[\SensitiveParameter] string $privacy_passphrase,
array|string $object_id, int $timeout = -1, int $retries = -1): mixed {}
function snmp3_getnext(
string $hostname, string $security_name, string $security_level,
- string $auth_protocol, string $auth_passphrase,
- string $privacy_protocol, string $privacy_passphrase,
+ string $auth_protocol, #[\SensitiveParameter] string $auth_passphrase,
+ string $privacy_protocol, #[\SensitiveParameter] string $privacy_passphrase,
array|string $object_id, int $timeout = -1, int $retries = -1): mixed {}
function snmp3_walk(
string $hostname, string $security_name, string $security_level,
- string $auth_protocol, string $auth_passphrase,
- string $privacy_protocol, string $privacy_passphrase,
+ string $auth_protocol, #[\SensitiveParameter] string $auth_passphrase,
+ string $privacy_protocol, #[\SensitiveParameter] string $privacy_passphrase,
array|string $object_id, int $timeout = -1, int $retries = -1): array|false {}
function snmp3_real_walk(
string $hostname, string $security_name, string $security_level,
- string $auth_protocol, string $auth_passphrase,
- string $privacy_protocol, string $privacy_passphrase,
+ string $auth_protocol, #[\SensitiveParameter] string $auth_passphrase,
+ string $privacy_protocol, #[\SensitiveParameter] string $privacy_passphrase,
array|string $object_id, int $timeout = -1, int $retries = -1): array|false {}
function snmp3_set(
string $hostname, string $security_name, string $security_level,
- string $auth_protocol, string $auth_passphrase,
- string $privacy_protocol, string $privacy_passphrase,
+ string $auth_protocol, #[\SensitiveParameter] string $auth_passphrase,
+ string $privacy_protocol, #[\SensitiveParameter] string $privacy_passphrase,
array|string $object_id, array|string $type, array|string $value,
int $timeout = -1, int $retries = -1): bool {}
@@ -239,15 +239,15 @@ class SNMP
public int $oid_output_format;
public int $exceptions_enabled;
- public function __construct(int $version, string $hostname, string $community, int $timeout = -1, int $retries = -1) {}
+ public function __construct(int $version, string $hostname, #[\SensitiveParameter] string $community, int $timeout = -1, int $retries = -1) {}
/** @tentative-return-type */
public function close(): bool {}
/** @tentative-return-type */
public function setSecurity(
- string $securityLevel, string $authProtocol = "", string $authPassphrase = "",
- string $privacyProtocol = "", string $privacyPassphrase = "",
+ string $securityLevel, string $authProtocol = "", #[\SensitiveParameter] string $authPassphrase = "",
+ string $privacyProtocol = "", #[\SensitiveParameter] string $privacyPassphrase = "",
string $contextName = "", string $contextEngineId = ""): bool {}
/** @tentative-return-type */
diff --git a/ext/snmp/snmp_arginfo.h b/ext/snmp/snmp_arginfo.h
index 1e134c62764..5e8af709928 100644
Binary files a/ext/snmp/snmp_arginfo.h and b/ext/snmp/snmp_arginfo.h differ
diff --git a/ext/snmp/snmp_decl.h b/ext/snmp/snmp_decl.h
index 78fad4608a2..f0b7f49d5a3 100644
Binary files a/ext/snmp/snmp_decl.h and b/ext/snmp/snmp_decl.h differ
diff --git a/ext/snmp/tests/sensitive_parameter.phpt b/ext/snmp/tests/sensitive_parameter.phpt
new file mode 100644
index 00000000000..a17457743d0
--- /dev/null
+++ b/ext/snmp/tests/sensitive_parameter.phpt
@@ -0,0 +1,35 @@
+--TEST--
+Test that community strings and SNMPv3 passphrases are marked sensitive.
+--EXTENSIONS--
+snmp
+--FILE--
+<?php
+try {
+ var_dump(snmpget('127.0.0.1', 'public', new stdClass));
+} catch (\Throwable $e) {
+ echo $e, PHP_EOL;
+}
+try {
+ var_dump(snmp3_get('127.0.0.1', 'user', 'authPriv', 'MD5', 'auth-pass', 'DES', 'priv-pass', new stdClass));
+} catch (\Throwable $e) {
+ echo $e, PHP_EOL;
+}
+try {
+ new SNMP(SNMP::VERSION_1, '127.0.0.1', 'public', 'not-an-int');
+} catch (\Throwable $e) {
+ echo $e, PHP_EOL;
+}
+?>
+--EXPECTF--
+TypeError: snmpget(): Argument #3 ($object_id) must be of type array|string, stdClass given in %s:%d
+Stack trace:
+#0 %s(%d): snmpget('127.0.0.1', Object(SensitiveParameterValue), Object(stdClass))
+#1 {main}
+TypeError: snmp3_get(): Argument #8 ($object_id) must be of type array|string, stdClass given in %s:%d
+Stack trace:
+#0 %s(%d): snmp3_get('127.0.0.1', 'user', 'authPriv', 'MD5', Object(SensitiveParameterValue), 'DES', Object(SensitiveParameterValue), Object(stdClass))
+#1 {main}
+TypeError: SNMP::__construct(): Argument #4 ($timeout) must be of type int, string given in %s:%d
+Stack trace:
+#0 %s(%d): SNMP->__construct(0, '127.0.0.1', Object(SensitiveParameterValue), 'not-an-int')
+#1 {main}
diff --git a/ext/sodium/libsodium.stub.php b/ext/sodium/libsodium.stub.php
index 80d8de2c0b2..f1fefefe65e 100644
--- a/ext/sodium/libsodium.stub.php
+++ b/ext/sodium/libsodium.stub.php
@@ -696,12 +696,12 @@ function sodium_crypto_pwhash_scryptsalsa208sha256_str(#[\SensitiveParameter] st
function sodium_crypto_pwhash_scryptsalsa208sha256_str_verify(string $hash, #[\SensitiveParameter] string $password): bool {}
#endif
-function sodium_crypto_scalarmult(string $n, string $p): string {}
+function sodium_crypto_scalarmult(#[\SensitiveParameter] string $n, string $p): string {}
#ifdef crypto_core_ristretto255_HASHBYTES
-function sodium_crypto_scalarmult_ristretto255(string $n, string $p): string {}
+function sodium_crypto_scalarmult_ristretto255(#[\SensitiveParameter] string $n, string $p): string {}
-function sodium_crypto_scalarmult_ristretto255_base(string $n): string {}
+function sodium_crypto_scalarmult_ristretto255_base(#[\SensitiveParameter] string $n): string {}
#endif
function sodium_crypto_secretbox(#[\SensitiveParameter] string $message, string $nonce, #[\SensitiveParameter] string $key): string {}
diff --git a/ext/sodium/libsodium_arginfo.h b/ext/sodium/libsodium_arginfo.h
index fbeb30fdd63..d13759fd75f 100644
Binary files a/ext/sodium/libsodium_arginfo.h and b/ext/sodium/libsodium_arginfo.h differ
diff --git a/ext/sodium/tests/sensitive_parameter.phpt b/ext/sodium/tests/sensitive_parameter.phpt
new file mode 100644
index 00000000000..95b1af2c153
--- /dev/null
+++ b/ext/sodium/tests/sensitive_parameter.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Test that the secret scalar parameter of sodium_crypto_scalarmult*() is marked sensitive.
+--EXTENSIONS--
+sodium
+--FILE--
+<?php
+foreach ([
+ 'sodium_crypto_scalarmult',
+ 'sodium_crypto_scalarmult_base',
+ 'sodium_crypto_scalarmult_ristretto255',
+ 'sodium_crypto_scalarmult_ristretto255_base',
+] as $function) {
+ $parameter = (new ReflectionFunction($function))->getParameters()[0];
+ echo $function, '($', $parameter->getName(), '): ';
+ var_dump(array_map(fn (ReflectionAttribute $a) => $a->getName(), $parameter->getAttributes()));
+}
+?>
+--EXPECT--
+sodium_crypto_scalarmult($n): array(1) {
+ [0]=>
+ string(18) "SensitiveParameter"
+}
+sodium_crypto_scalarmult_base($secret_key): array(1) {
+ [0]=>
+ string(18) "SensitiveParameter"
+}
+sodium_crypto_scalarmult_ristretto255($n): array(1) {
+ [0]=>
+ string(18) "SensitiveParameter"
+}
+sodium_crypto_scalarmult_ristretto255_base($n): array(1) {
+ [0]=>
+ string(18) "SensitiveParameter"
+}
diff --git a/ext/sqlite3/sqlite3.stub.php b/ext/sqlite3/sqlite3.stub.php
index 1a51f9dc3d8..c30b6e08c0d 100644
--- a/ext/sqlite3/sqlite3.stub.php
+++ b/ext/sqlite3/sqlite3.stub.php
@@ -162,13 +162,13 @@ class SQLite3
#endif
/** @implementation-alias SQLite3::open */
- public function __construct(string $filename, int $flags = SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE, string $encryptionKey = "") {}
+ public function __construct(string $filename, int $flags = SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE, #[\SensitiveParameter] string $encryptionKey = "") {}
/**
* @tentative-return-type
* @todo SQLite3::open should really be static
*/
- public function open(string $filename, int $flags = SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE, string $encryptionKey = ""): void {}
+ public function open(string $filename, int $flags = SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE, #[\SensitiveParameter] string $encryptionKey = ""): void {}
/** @tentative-return-type */
public function close(): bool {}
diff --git a/ext/sqlite3/sqlite3_arginfo.h b/ext/sqlite3/sqlite3_arginfo.h
index 3917ef63e28..f3f8160e5e2 100644
Binary files a/ext/sqlite3/sqlite3_arginfo.h and b/ext/sqlite3/sqlite3_arginfo.h differ
diff --git a/ext/sqlite3/tests/sensitive_parameter.phpt b/ext/sqlite3/tests/sensitive_parameter.phpt
new file mode 100644
index 00000000000..24807013f63
--- /dev/null
+++ b/ext/sqlite3/tests/sensitive_parameter.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Test that the encryption key parameter of SQLite3::__construct() and SQLite3::open() is marked sensitive.
+--EXTENSIONS--
+sqlite3
+--FILE--
+<?php
+try {
+ new SQLite3(':memory:', 'not-an-int', 'secret-key');
+} catch (\Throwable $e) {
+ echo $e, PHP_EOL;
+}
+try {
+ $db = (new ReflectionClass(SQLite3::class))->newInstanceWithoutConstructor();
+ $db->open(':memory:', 'not-an-int', 'secret-key');
+} catch (\Throwable $e) {
+ echo $e, PHP_EOL;
+}
+?>
+--EXPECTF--
+TypeError: SQLite3::__construct(): Argument #2 ($flags) must be of type int, string given in %s:%d
+Stack trace:
+#0 %s(%d): SQLite3->__construct(':memory:', 'not-an-int', Object(SensitiveParameterValue))
+#1 {main}
+TypeError: SQLite3::open(): Argument #2 ($flags) must be of type int, string given in %s:%d
+Stack trace:
+#0 %s(%d): SQLite3->open(':memory:', 'not-an-int', Object(SensitiveParameterValue))
+#1 {main}