<div dir="ltr"><div style="font-size:13px">Hi,</div><div style="font-size:13px"><br></div><div style="font-size:13px">php-openid library treats %0A/%0D characters in hostname of an openid endpoint URL as valid and decodes them into special characters \r\n right before making a discovery request to that location. When it uses curl to make web requests, and I guess this is a recommended way, libcurl passes these invalid URLs to the TCP stream in certain cases, for example, when it is configured to work through proxy. With this discovery logic php-openid allows to craft arbitrary requests inside the org network or to a loopback server interface, which exposes the infrastructure to the outside and is quite bad.</div><div style="font-size:13px"><br></div><div style="font-size:13px">For some reason, hostnames are converted in an unsafe way:</div><div style="font-size:13px"><a href="https://github.com/openid/php-openid/blob/0ef9be71c1ff6114d04bc93d5156c00b25653a1b/Auth/OpenID/URINorm.php#L205" target="_blank">https://github.com/openid/php-openid/blob/0ef9be71c1ff6114d04bc93d5156c00b25653a1b/Auth/OpenID/URINorm.php#L205</a></div><div style="font-size:13px"><br></div><div style="font-size:13px"><div>  function Auth_OpenID_pct_encoded_replace($mo)</div><div>  {</div><div>      return chr(intval($mo[1], 16));</div><div>  }</div></div><div style="font-size:13px">  ...</div><div style="font-size:13px">  if (strpos($host, '%') !== -1) {</div><div style="font-size:13px">      $host = strtolower($host);</div><div style="font-size:13px">      $host = preg_replace_callback(</div><div style="font-size:13px">                Auth_OpenID_getEncodedPattern(),</div><div style="font-size:13px">                'Auth_OpenID_pct_encoded_replace', $host);       // <------------</div><div style="font-size:13px">                </div><div style="font-size:13px">..in contrast with path:</div><div style="font-size:13px">  </div><div style="font-size:13px">  function Auth_OpenID_pct_encoded_replace_unreserved($mo)</div><div style="font-size:13px">  {</div><div style="font-size:13px">      $_unreserved = Auth_OpenID_getUnreserved();</div><div style="font-size:13px">      $i = intval($mo[1], 16);</div><div style="font-size:13px">      if ($_unreserved[$i]) {</div><div style="font-size:13px">          return chr($i);</div><div style="font-size:13px">      } else {</div><div style="font-size:13px">          return strtoupper($mo[0]);</div><div style="font-size:13px">      }</div><div style="font-size:13px">      return $mo[0];</div><div style="font-size:13px">  }</div><div style="font-size:13px">  ...</div><div style="font-size:13px">  $path = preg_replace_callback(</div><div style="font-size:13px">         Auth_OpenID_getEncodedPattern(),</div><div style="font-size:13px">         'Auth_OpenID_pct_encoded_replace_unreserved', $path);  // <----------</div><div style="font-size:13px">  </div><div style="font-size:13px">         </div><div style="font-size:13px">Please, have a look at the attached diff, this should resolve the problem.</div><div style="font-size:13px"><br></div><div style="font-size:13px">Thanks,</div><div style="font-size:13px">Andrey Labunets</div></div>