{"id":"GHSA-82vx-mm6r-gg8w","summary":"Bref vulnerable to Body Parsing Inconsistency in Event-Driven Functions","details":"## Impacted Resources\n\nbref/src/Event/Http/Psr7Bridge.php:130-168\n\n## Description\n\nWhen Bref is used with the Event-Driven Function runtime and the handler is a `RequestHandlerInterface`, then the Lambda event is converted to a PSR7 object.\nDuring the conversion process, if the request is a MultiPart, each part is parsed and its content added in the `$files` or `$parsedBody` arrays.\nTo do that, the following method is called with as first argument the result array (`$files` or `$parsedBody`), as second argument the part name, and as third argument the part content:\n\n```php\n/**\n * Parse a string key like \"files[id_cards][jpg][]\" and do $array['files']['id_cards']['jpg'][] = $value\n */\nprivate static function parseKeyAndInsertValueInArray(array &$array, string $key, mixed $value): void\n{\n    if (! str_contains($key, '[')) {\n        $array[$key] = $value;\n\n        return;\n    }\n\n    $parts = explode('[', $key); // files[id_cards][jpg][] =\u003e [ 'files',  'id_cards]', 'jpg]', ']' ]\n    $pointer = &$array;\n\n    foreach ($parts as $k =\u003e $part) {\n        if ($k === 0) {\n            $pointer = &$pointer[$part];\n\n            continue;\n        }\n\n        // Skip two special cases:\n        // [[ in the key produces empty string\n        // [test : starts with [ but does not end with ]\n        if ($part === '' || ! str_ends_with($part, ']')) {\n            // Malformed key, we use it \"as is\"\n            $array[$key] = $value;\n\n            return;\n        }\n\n        $part = substr($part, 0, -1); // The last char is a ] =\u003e remove it to have the real key\n\n        if ($part === '') { // [] case\n            $pointer = &$pointer[];\n        } else {\n            $pointer = &$pointer[$part];\n        }\n    }\n\n    $pointer = $value;\n}\n```\n\nThe conversion process produces a different output compared to the one of plain PHP when keys ending with and open square bracket (`[`) are used.\n\nLet's take for example the following part:\n```\n------WebKitFormBoundary\nContent-Disposition: form-data; name=\"key0[key1][key2][\"\n\nvalue\n------WebKitFormBoundary--\n```\n\nIn plain PHP it would be converted to `Array( [key0] =\u003e Array ( [key1] =\u003e Array ( [key2] =\u003e value) ) )`, while in Bref it would be converted to `Array( [key0] =\u003e Array ( [key1] =\u003e Array ( [key2] =\u003e  ) ) [key0[key1][key2][] =\u003e value )`.\n\n## Impact\n\nBased on the application logic the difference in the body parsing might lead to vulnerabilities and/or undefined behaviors.\n\n## PoC\n\n1. Create a new Bref project.\n2. Create an `index.php` file with the following content:\n```php\n\u003c?php\n\nnamespace App;\n\nrequire __DIR__ . '/vendor/autoload.php';\n\nuse Nyholm\\Psr7\\Response;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\n\nclass MyHttpHandler implements RequestHandlerInterface\n{\n    public function handle(ServerRequestInterface $request): ResponseInterface\n    {\n\n        return new Response(200, [], var_export($request-\u003egetParsedBody(),true));\n    }\n}\n\nreturn new MyHttpHandler();\n\n```\n3. Use the following `serverless.yml` to deploy the Lambda:\n```yaml\nservice: app\n\nprovider:\n    name: aws\n    region: eu-central-1\n\nplugins:\n    - ./vendor/bref/bref\n\n# Exclude files from deployment\npackage:\n    patterns:\n        - '!node_modules/**'\n        - '!tests/**'\n\nfunctions:\n    api:\n        handler: index.php\n        runtime: php-83\n        events:\n            - httpApi: 'ANY /upload'\n```\n4. Replay the following request after having replaced the `\u003cHOST\u003e` placeholder with the deployed Lambda domain:\n```\nPOST /upload HTTP/2\nHost: \u003cHOST\u003e\nContent-Type: multipart/form-data; boundary=----WebKitFormBoundaryQqDeSZSSvmn2rfjb\nContent-Length: 180\n\n------WebKitFormBoundaryQqDeSZSSvmn2rfjb\nContent-Disposition: form-data; name=\"key0[key1][key2][\"\n\nvalue\n------WebKitFormBoundaryQqDeSZSSvmn2rfjb--\n```\n5. Notice how the body has been parsed.\n6. Create a `plain.php` file with the following content:\n```php\n\u003c?php\n\nvar_dump($_POST);\n```\n7. Start a PHP server inside the project directory (e.g. `php -S 127.0.0.1:8090`).\n8. Replay the following request after having replaced the `\u003cHOST\u003e` placeholder with the PHP server address:\n```\nPOST /plain.php HTTP/1.1\nHost: \u003cHOST\u003e\nContent-Type: multipart/form-data; boundary=----WebKitFormBoundaryQqDeSZSSvmn2rfjb\nContent-Length: 180\n\n------WebKitFormBoundaryQqDeSZSSvmn2rfjb\nContent-Disposition: form-data; name=\"key0[key1][key2][\"\n\nvalue\n------WebKitFormBoundaryQqDeSZSSvmn2rfjb--\n```\n9. Notice the differences in the parsing compared to what observed at step 5.\n\n## Suggested Remediation\n\nUse the PHP function [`parse_str`](https://www.php.net/manual/en/function.parse-str.php) to parse the body parameters to mimic the plain PHP behavior.","aliases":["CVE-2024-24754"],"modified":"2026-09-10T03:50:05.466188695Z","published":"2024-02-01T22:47:29Z","database_specific":{"severity":"LOW","github_reviewed":true,"github_reviewed_at":"2024-02-01T22:47:29Z","nvd_published_at":"2024-02-01T16:17:14Z","cwe_ids":["CWE-436"]},"references":[{"type":"WEB","url":"https://github.com/brefphp/bref/security/advisories/GHSA-82vx-mm6r-gg8w"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2024-24754"},{"type":"WEB","url":"https://github.com/brefphp/bref/commit/c77d9f5abf021f29fa96b5720b7b84adbd199092"},{"type":"PACKAGE","url":"https://github.com/brefphp/bref"},{"type":"WEB","url":"https://github.com/brefphp/bref/blob/2.1.12/src/Event/Http/Psr7Bridge.php#L130-L168"}],"affected":[{"package":{"name":"bref/bref","ecosystem":"Packagist","purl":"pkg:composer/bref/bref"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.1.13"}]}],"versions":["0.1.0","0.2.0","0.2.1","0.2.10","0.2.11","0.2.12","0.2.13","0.2.14","0.2.15","0.2.16","0.2.17","0.2.18","0.2.19","0.2.2","0.2.20","0.2.21","0.2.22","0.2.23","0.2.24","0.2.25","0.2.26","0.2.27","0.2.28","0.2.29","0.2.3","0.2.30","0.2.31","0.2.32","0.2.33","0.2.34","0.2.35","0.2.36","0.2.37","0.2.4","0.2.5","0.2.6","0.2.7","0.2.8","0.2.9","0.3.0","0.3.1","0.3.2","0.3.3","0.3.4","0.3.5","0.3.6","0.3.7","0.3.8","0.3.9","0.4.0","0.4.1","0.5.0","0.5.0-beta1","0.5.1","0.5.10","0.5.11","0.5.12","0.5.13","0.5.14","0.5.14-beta1","0.5.14-beta2","0.5.15","0.5.16","0.5.17","0.5.18","0.5.19","0.5.2","0.5.20","0.5.21","0.5.22","0.5.23","0.5.24","0.5.25","0.5.26","0.5.27","0.5.28","0.5.29","0.5.3","0.5.30","0.5.31","0.5.32","0.5.33","0.5.4","0.5.5","0.5.6","0.5.6-beta1","0.5.7","0.5.8","0.5.9","1.0.0","1.0.0-beta1","1.0.0-beta2","1.0.1","1.0.2","1.1.0","1.1.1","1.1.2","1.1.3","1.1.4","1.2.0","1.2.1","1.2.10","1.2.11","1.2.12","1.2.13","1.2.14","1.2.2","1.2.3","1.2.4","1.2.5","1.2.6","1.2.7","1.2.8","1.2.9","1.3.0","1.3.1","1.3.2","1.3.3","1.3.4","1.3.5","1.3.6","1.4.0","1.4.1","1.4.2","1.5.0","1.5.1","1.5.2","1.5.3","1.5.4","1.5.5","1.5.6","1.5.7","1.5.8","1.6.0","1.7.0","1.7.1","1.7.10","1.7.11","1.7.12","1.7.13","1.7.14","1.7.15","1.7.16","1.7.17","1.7.18","1.7.19","1.7.2","1.7.20","1.7.21","1.7.22","1.7.23","1.7.24","1.7.25","1.7.26","1.7.27","1.7.28","1.7.29","1.7.3","1.7.30","1.7.31","1.7.32","1.7.33","1.7.34","1.7.35","1.7.36","1.7.37","1.7.38","1.7.39","1.7.4","1.7.40","1.7.41","1.7.42","1.7.43","1.7.44","1.7.45","1.7.46","1.7.47","1.7.5","1.7.6","1.7.7","1.7.8","1.7.9","2.0.0","2.0.0-beta1","2.0.0-beta10","2.0.0-beta11","2.0.0-beta12","2.0.0-beta13","2.0.0-beta14","2.0.0-beta15","2.0.0-beta16","2.0.0-beta17","2.0.0-beta2","2.0.0-beta3","2.0.0-beta4","2.0.0-beta5","2.0.0-beta6","2.0.0-beta7","2.0.0-beta8","2.0.0-beta9","2.0.1","2.0.10","2.0.11","2.0.2","2.0.3","2.0.4","2.0.5","2.0.6","2.0.7","2.0.8","2.0.9","2.1.0","2.1.1","2.1.10","2.1.11","2.1.12","2.1.2","2.1.3","2.1.4","2.1.5","2.1.6","2.1.7","2.1.8","2.1.9"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2024/02/GHSA-82vx-mm6r-gg8w/GHSA-82vx-mm6r-gg8w.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N"}]}