Fix issue - #445
Conversation
| size_t pos = filenameStr.find(phpResourceString); | ||
| if (pos != std::string::npos) { | ||
| return filenameStr.substr(pos + phpResourceString.length()); |
There was a problem hiding this comment.
🟠 High - Nested php://filter wrappers now evade SSRF enforcement
Switching php://filter parsing to a single first-/resource= extraction means payloads such as php://filter/resource=php://filter/resource=http://169.254.169.254/... are now reduced only to the inner wrapper string, not to the final URL PHP will fetch. In helper_handle_pre_file_path_access, that value no longer starts with http:// or https://, so the sink is reclassified as EVENT_PRE_PATH_ACCESSED and no SSRF pre/post handlers run. An attacker who can influence a fopen-style path can therefore wrap an internal URL in a nested filter and bypass the firewall's SSRF protection for that request.
Show fix
Preserve the first-/resource= behavior for each wrapper layer, but keep unwrapping while the extracted resource itself is another php://filter stream. Apply the same recursive normalization in both the PHP extension and the Go helper used by hostname/path checks so nested wrappers resolve to the final target URL before event classification or SSRF matching.
More info - Reply on this comment to give feedback or ignore the issue.
Fix implemented.
This draft was generated after automated triage and requires maintainer review.