HttpSignatureService::verifySignature() checks the result of PHP's openssl_verify() with a loose boolean negation - if (!openssl_verify(...)) { throw ... }. PHP's openssl_verify has four possible return values:
| return | meaning | !return |
| ------ | ------------------------------------------------ | --------- |
| 1 | signature is valid | false |
| 0 | signature is invalid | true ✓ |
| -1 | the verify call itself failed (internal error) | false ❌ |
| false| input rejected by PHP's argument validation | true ✓ |
The -1 row is the bypass: PHP's truthiness rules make -1 a truthy value, so !(-1) === false, the throw is skipped, and the controller proceeds to processActivity(). Any condition that makes OpenSSL's EVP_VerifyFinal() return -1 triggers the bypass.
The two practical paths to -1 we are aware of:
openssl_verify(..., $dsaKey, "RSA-SHA256") returns int(-1) on PHP 8.3 + OpenSSL 3.x. This is the path the PoC uses; it works against an unmodified php:8.3-apache lab and against any deployment using the runtime stack YesWiki's own docker image ships.-1 rather than false. The reporting research mentions this path; on current stacks false is returned instead and the throw fires correctly. The DSA path replaces it.The reachable consequence is the same in both cases - the controller silently treats a failed verification as success and processes the attacker's payload.
tools/bazar/services/HttpSignatureService.phpHttpSignatureService::verifySignature(Request $request)// tools/bazar/services/HttpSignatureService.php (v4.6.5 = origin/doryphore-dev...
4.6.6Exploitability
AV:NAC:LPR:NUI:NScope
S:UImpact
C:NI:HA:L8.2/CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:LOther