BookStackApp/BookStack · error · HttpFetchException

errors.http_ssr_url_no_match

Error message

errors.http_ssr_url_no_match

What it means

SsrUrlValidator::ensureAllowed() throws HttpFetchException with errors.http_ssr_url_no_match when the supplied URL does not match any configured allowed SSR host pattern. BookStack validates outbound URLs (used for fetching remote resources such as avatars) against the 'allow' host list to prevent SSRF attacks to internal networks.

Source

Thrown at app/Util/SsrUrlValidator.php:31

 * protocol and host. It can optionally define a path prefix as part of the URL.
 * Wildcards, via a '*', can be used within these elements to match anything but a '/'.
 */
class SsrUrlValidator
{
    protected string $config;

    public function __construct(?string $config = null)
    {
        $this->config = $config ?? config('app.ssr_hosts') ?? '';
    }

    /**
     * @throws HttpFetchException
     */
    public function ensureAllowed(string $url): void
    {
        if (!$this->allowed($url)) {
            throw new HttpFetchException(trans('errors.http_ssr_url_no_match'));
        }
    }

    /**
     * Check if the given URL is allowed by the configured SSR host values.
     */
    public function allowed(string $url): bool
    {
        $allowed = $this->getHostPatterns();

        foreach ($allowed as $pattern) {
            if ($this->urlMatchesPattern($url, $pattern)) {
                return true;
            }
        }

        return false;
    }

View on GitHub (pinned to 18f8469a1c)

Solutions

  1. Add the URL's host to the SSR allowed hosts configuration (e.g. via the allow-list settings/REGEX host patterns)
  2. Verify allowed($url) matching logic: scheme, case, port and wildcards in your patterns
  3. Catch HttpFetchException and surface the SSR-block message; do not retry the same URL
  4. Audit requested URLs for redirects that land on non-allowed hosts

Example fix

// before
(new SsrUrlValidator())->ensureAllowed('https://internal.example.com/avatar.png');
// after
// config: allowed hosts includes 'internal.example.com'
(new SsrUrlValidator())->ensureAllowed('https://internal.example.com/avatar.png');
Defensive patterns

Strategy: validation

Validate before calling

// Validate the URL host against your allowed SSR hosts before fetching
$parsed = parse_url($url, PHP_URL_HOST);
$allowed = ['example.com', 'cdn.example.com']; // mirror your configured SSR allowlist
if (!in_array(strtolower((string) $parsed), $allowed, true)) {
    throw new \InvalidArgumentException("Host not allowed for SSR fetch: {$parsed}");
}

Try / catch

try {
    (new \BookStack\Util\SsrUrlValidator())->ensureAllowed($url);
} catch (\BookStack\Exceptions\HttpFetchException $e) {
    abort(400, 'URL blocked by SSRF protection');
}

Prevention

When it happens

Trigger: Any code path calling ensureAllowed($url) (avatar/image fetch flows) where $url's host fails the allowed($url) check against configured allowed hosts — e.g. hosts not whitelisted, or misparsed host values.

Common situations: Empty or overly narrow APP/SSR allowed-hosts configuration; hosts with different scheme/port/case not matching patterns; internal IPs (10.x, 169.254.x, localhost) blocked by default SSRF guards; environment migrations where the allowlist wasn't updated.

Related errors


AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02). Data as JSON: /api/errors/74b58cf97b191358. Report an issue: GitHub.