VYPR
Medium severity5.4OSV Advisory· Published May 22, 2024· Updated Apr 15, 2026

CVE-2024-25737

CVE-2024-25737

Description

A Server-Side Request Forgery (SSRF) vulnerability in the /Cover/Show route (showAction in CoverController.php) in Open Library Foundation VuFind 2.4 through 9.1 before 9.1.1 allows remote attackers to access internal HTTP servers and perform Cross-Site Scripting (XSS) attacks by proxying arbitrary URLs via the proxy GET parameter.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

SSRF in VuFind cover proxy allows internal network access and XSS via unvalidated URL proxying.

Vulnerability

A Server-Side Request Forgery (SSRF) vulnerability exists in the /Cover/Show route (showAction in CoverController.php) of VuFind versions 2.4 through 9.1 before 9.1.1. The proxy GET parameter is not properly validated, allowing an attacker to force the server to fetch arbitrary URLs. This enables access to internal HTTP servers and can be leveraged for Cross-Site Scripting (XSS) attacks by proxying malicious content such as SVG files [1].

Exploitation

No authentication is required to exploit this vulnerability. An attacker can craft a request to the cover proxy endpoint with a URL pointing to an internal service (e.g., http://internal-service/) or to a malicious external resource. The server will fetch and return the content, potentially exposing sensitive internal data or delivering XSS payloads to users who view the proxied image. The lack of restriction on allowed hostnames or content types prior to the fix made exploitation straightforward [1].

Impact

Successful exploitation allows an attacker to scan internal networks, access restricted services, and execute arbitrary JavaScript in the context of the VuFind application. This can lead to data theft, session hijacking, or further compromise of the internal infrastructure. The SSRF component also enables blind probing of internal systems [1].

Mitigation

The vulnerability has been patched in VuFind 9.1.1. The fix introduces configuration options to restrict allowed hostnames via coverproxyAllowedHosts (e.g., only allowing specific domains like assets.thirdiron.com and .summon.serialssolutions.com) [2] and to limit permissible content types to safe image formats (image/gif, image/jpeg, image/png) via coverproxyAllowedTypes [3]. Administrators are strongly advised to upgrade to the latest version and review their proxy configuration.

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
vufind/vufindPackagist
>= 2.4, < 9.1.19.1.1

Affected products

3

Patches

3
51f2ddac0dc1

Make cover proxy legal content types configurable. (#3388)

https://github.com/vufind-org/vufindDemian KatzFeb 6, 2024via ghsa
2 files changed · +24 1
  • config/vufind/config.ini+7 0 modified
    @@ -1030,6 +1030,13 @@ coverproxyCache[] = "/assets\.thirdiron\.com/"
     coverproxyAllowedHosts[] = "/assets\.thirdiron\.com$/"
     coverproxyAllowedHosts[] = "/\.summon\.serialssolutions\.com$/"
     
    +; This setting controls the content types allowed through the cover proxy.
    +; Note that proxying SVG files is not recommended because of their potential for
    +; abuse in cross-site scripting attacks.
    +coverproxyAllowedTypes[] = "image/gif"
    +coverproxyAllowedTypes[] = "image/jpeg"
    +coverproxyAllowedTypes[] = "image/png"
    +
     ; This setting controls how cover image URLs are loaded. They could be loaded as
     ; part of main request, or asynchronously. Asynchronous loading is disabled by
     ; default; to enable it, just uncomment the line below.
    
  • module/VuFind/src/VuFind/Controller/CoverController.php+17 1 modified
    @@ -33,6 +33,8 @@
     use VuFind\Cover\Loader;
     use VuFind\Session\Settings as SessionSettings;
     
    +use function in_array;
    +
     /**
      * Generates covers for book entries
      *
    @@ -146,6 +148,20 @@ protected function proxyAllowedForUrl(string $url): bool
             return false;
         }
     
    +    /**
    +     * Is the content type allowed by the cover proxy?
    +     *
    +     * @param string $contentType Type to check
    +     *
    +     * @return bool
    +     */
    +    protected function isValidProxyImageContentType(string $contentType): bool
    +    {
    +        $validTypes = $this->config['coverproxyAllowedTypes']
    +            ?? ['image/gif', 'image/jpeg', 'image/png'];
    +        return in_array(strtolower($contentType), array_map('strtolower', $validTypes));
    +    }
    +
         /**
          * Send image data for display in the view
          *
    @@ -161,7 +177,7 @@ public function showAction()
                 try {
                     $image = $this->proxy->fetch($url);
                     $contentType = $image?->getHeaders()?->get('content-type')?->getFieldValue() ?? '';
    -                if (str_starts_with(strtolower($contentType), 'image/')) {
    +                if ($this->isValidProxyImageContentType($contentType)) {
                         return $this->displayImage(
                             $contentType,
                             $image->getContent()
    
345d00f7d7f1

Restrict hostnames for cover proxy. (#3385)

https://github.com/vufind-org/vufindDemian KatzFeb 6, 2024via ghsa
3 files changed · +44 3
  • config/vufind/config.ini+7 0 modified
    @@ -1023,6 +1023,13 @@ coverimagesCache = true
     ; BrowZine DOI icons:
     coverproxyCache[] = "/assets\.thirdiron\.com/"
     
    +; This setting controls which hosts are allowed to provide cover images through
    +; the built-in cover proxy. Images from hostnames that do not match the regular
    +; expressions below will not be proxied. Be sure to define regular expressions
    +; using an end of string ($) marker to prevent abuse.
    +coverproxyAllowedHosts[] = "/assets\.thirdiron\.com$/"
    +coverproxyAllowedHosts[] = "/\.summon\.serialssolutions\.com$/"
    +
     ; This setting controls how cover image URLs are loaded. They could be loaded as
     ; part of main request, or asynchronously. Asynchronous loading is disabled by
     ; default; to enable it, just uncomment the line below.
    
  • module/VuFind/src/VuFind/Controller/CoverControllerFactory.php+4 1 modified
    @@ -68,10 +68,13 @@ public function __invoke(
             if (!empty($options)) {
                 throw new \Exception('Unexpected options sent to factory.');
             }
    +        $config = $container->get(\VuFind\Config\PluginManager::class)->get('config');
    +        $configArray = $config?->Content?->toArray() ?? [];
             return new $requestedName(
                 $container->get(\VuFind\Cover\Loader::class),
                 $container->get(\VuFind\Cover\CachingProxy::class),
    -            $container->get(\VuFind\Session\Settings::class)
    +            $container->get(\VuFind\Session\Settings::class),
    +            $configArray
             );
         }
     }
    
  • module/VuFind/src/VuFind/Controller/CoverController.php+33 2 modified
    @@ -65,21 +65,31 @@ class CoverController extends \Laminas\Mvc\Controller\AbstractActionController
          */
         protected $sessionSettings = null;
     
    +    /**
    +     * Configuration settings ([Content] section of config.ini)
    +     *
    +     * @var array
    +     */
    +    protected $config;
    +
         /**
          * Constructor
          *
          * @param Loader          $loader Cover loader
          * @param CachingProxy    $proxy  Proxy loader
          * @param SessionSettings $ss     Session settings
    +     * @param array           $config Configuration settings
          */
         public function __construct(
             Loader $loader,
             CachingProxy $proxy,
    -        SessionSettings $ss
    +        SessionSettings $ss,
    +        array $config = []
         ) {
             $this->loader = $loader;
             $this->proxy = $proxy;
             $this->sessionSettings = $ss;
    +        $this->config = $config;
         }
     
         /**
    @@ -115,6 +125,27 @@ protected function getImageParams()
             ];
         }
     
    +    /**
    +     * Is the provided URL included on the configured allow list?
    +     *
    +     * @param string $url URL to check
    +     *
    +     * @return bool
    +     */
    +    protected function proxyAllowedForUrl(string $url): bool
    +    {
    +        $host = parse_url($url, PHP_URL_HOST);
    +        if (!$host) {
    +            return false;
    +        }
    +        foreach ((array)($this->config['coverproxyAllowedHosts'] ?? []) as $regEx) {
    +            if (preg_match($regEx, $host)) {
    +                return true;
    +            }
    +        }
    +        return false;
    +    }
    +
         /**
          * Send image data for display in the view
          *
    @@ -126,7 +157,7 @@ public function showAction()
     
             // Special case: proxy a full URL:
             $url = $this->params()->fromQuery('proxy');
    -        if (!empty($url)) {
    +        if (!empty($url) && $this->proxyAllowedForUrl($url)) {
                 try {
                     $image = $this->proxy->fetch($url);
                     $contentType = $image?->getHeaders()?->get('content-type')?->getFieldValue() ?? '';
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.