Separate a displayed link from a server fetch
A customer pastes a URL into a product review, support ticket or profile. The application could simply display a safe link for a person to open, or it could fetch the destination on its own server to extract a title, preview image or remote file. Those are materially different operations. A server fetch reaches networks and credentials available to the application, not necessarily to the customer’s browser. OWASP describes server-side request forgery, or SSRF, as abuse of an application to interact with its own machine or internal and external network; remote images and callback URLs are among its examples. The first business decision is whether the preview or import genuinely helps the customer enough to justify that extra capability.
If the service only needs to let staff read a customer’s reference, storing the submitted string as untrusted content and presenting a clearly identified external link may meet the need. The application still needs ordinary output encoding and safe link handling, but no server-side network trip is required. If the service must inspect a supplier document or preview an approved marketplace listing, define the exact permitted business destinations and data to retrieve. Do not silently allow any URL because a feature is called a preview. A support agent’s legitimate workflow does not imply that the application should connect to arbitrary hosts chosen by a customer or by a compromised account.
Constrain the destination and the connection
OWASP’s SSRF prevention guidance favors allowlisting where the expected destinations are known. Parse the submitted URL with an established URL parser; define the accepted schemes, hosts and ports for the feature; and reject credentials embedded in a URL. A textual search for suspicious words is not an adequate security boundary. For a feature that really must reach arbitrary public sites, the design is harder: resolve both IPv4 and IPv6 answers, reject private, loopback, link-local and other disallowed ranges, and bind the actual connection to an address that passed validation. OWASP explicitly warns that a separate unchecked DNS lookup between validation and connection can defeat the check. Review the chosen HTTP client and networking path as one system.
Redirects need their own rule. A seemingly acceptable public URL can respond with a redirect to a different destination. OWASP advises disabling automatic redirect following for this use case, because it can bypass input validation. If the business needs to follow a redirect, treat every new location as a fresh untrusted URL and apply the complete destination policy again, with a small explicit hop limit and a final connection check. Do not carry authorization headers, cookies or internal credentials to a customer-controlled destination. A preview request should not inherit a staff member’s browser session or a server token intended for another service. These are design constraints, not claims that any specific site is already safe.
Network controls provide a second boundary. Route the fetcher through an egress policy that allows only the destinations it needs, and deny access to internal management services and cloud metadata endpoints. Keep the fetcher’s own credentials minimal. Set connection and overall timeouts, response size limits and accepted content types; a page that never finishes or returns a huge binary file should not occupy the service indefinitely. Treat received HTML, images and headers as untrusted data, even when the outbound connection itself was allowed. A safe destination check does not make the returned document trustworthy. Store only the metadata the feature needs and avoid copying customer-supplied remote content into a public page without suitable review and rendering controls.
Rehearse the feature with safe test destinations
Suppose a Hong Kong retailer wants support tickets to show previews only for links to its own help centre and one contracted supplier portal. An allowlist can express those two destinations; the preview service fetches only the limited metadata it needs. A customer then pastes a shortened link that redirects elsewhere. The client refuses automatic redirection and reports that the preview is unavailable, while preserving the original ticket text for a human to assess. If the supplier later changes its host, staff verify the new host through the supplier relationship and update the allowlist deliberately. They do not widen the rule to every public address merely to make one broken preview work.
Build test cases around the policy, not a list of notorious URLs. Include a permitted host, an unlisted host, an unsupported scheme, an embedded credential, a redirect to a denied destination, and a host whose DNS answer changes between checks. Include IPv6 and an address that is public-looking in text but resolves to an internal range. Verify that denied requests never reach the protected network in a controlled test environment. Also check timeouts, oversized responses and malformed content; the user interface must show a bounded, understandable preview failure without losing the original customer message. Logs should record the policy decision and destination category without copying secrets from a submitted URL.
Ownership matters after launch. Name who approves new destinations, who reviews a blocked-preview report, and who can temporarily disable the fetcher if its network boundary fails. Recheck allowed hosts and outbound permissions when the supplier contract or cloud environment changes. If the team cannot enforce connection-time address checks or inspect redirects reliably in its current stack, keep the simpler external-link experience until it can. The acceptance decision is observable: a legitimate allowed preview works; every disallowed route fails closed; and a customer can still submit a useful ticket when previewing is unavailable. That is a complete customer journey, not just a URL validator passing unit tests.
Choose a safe service boundary
There are several product choices between no preview and unrestricted fetching. A retailer may show only the submitted host name and let staff open the link manually. It may preview only its own help centre, or a small set of approved suppliers. It may accept a remote image only from an authenticated merchant integration rather than from every customer. Each choice has a different customer benefit and a different control surface. Write the policy in business language first: who may submit a URL, which feature uses it, what the server retrieves, what the customer sees on failure, and who can expand the destination list.
The URL may arrive indirectly. A background job can fetch a link stored in a database hours after the form was submitted; a support worker can paste a customer URL into an internal tool; an image processor can follow a remote asset referenced by another document. Inventory every component that turns stored text into an outbound request. Validation at the original web form is useful but cannot be the only control, because later jobs may read old data, imported records or values written through another interface. Put the destination check at the fetch boundary itself, then have upstream screens give early, understandable feedback where possible.
A blocked preview should not be framed as proof that the customer acted maliciously. The address could be unsupported, temporarily unresolvable or outside the service’s permitted suppliers. Explain the practical result: the message or reference was saved, but the preview was not generated; offer a way to correct the link or continue without a preview. For staff, show a concise reason category and an escalation route when a legitimate supplier moves domains. Avoid exposing detailed internal IP rules or network topology in customer messages. This keeps the security boundary firm without making an ordinary support journey feel like an accusation.
When reviewing an existing implementation, do not assume that a successful input check proves the system safe. Observe the actual outbound request from the fetcher in a controlled environment, including the address used after DNS resolution and any redirect behavior. Confirm that proxy settings, image libraries and headless browser helpers do not create a second unchecked route. The mitigation must survive a routine software update and a supplier domain change. Keep a short change record with the owner, purpose, allowed hosts and test results, so that a future maintainer can distinguish a deliberate exception from a forgotten broad permission.
Before you proceed
- Can the team explain why the server fetch is needed and list its permitted destinations?
- Do redirects, DNS changes and disallowed addresses fail without losing the customer message?


