Web Applications Security When Loading External Resources

By default, Aspose.Words for C++ can load remote resources such as images, CSS styles, or external HTML documents when importing documents or inserting images using the DocumentBuilder. This behavior allows you to process your documents in full detail but can be a reason of some security risks if the library is a part of a web application.

In this article, we take a look at common security issues that can arise when loading external resources and provide recommendations on how to avoid such problems.

Security Issues

There are a number of typical security problems when loading external resources.

Credential Disclosure Via Linked Images

On Windows-based hosts, documents containing references to resources that use UNC paths such as ‘\example.com\a\b’ will be processed by default. In a domain environment, this will cause the host to send its domain credentials in a hashed format to the specified server.

If an attacker is able to convince a user or server to process a document with such a resource link pointing to a host they control, the attacker will receive the user or service account credentials in NTLM hash format. Such data then can be reused in a classic pass-the-hash attack, allowing the attacker to gain access to any resource as the victim user or service account.

If the account in question uses a weak or guessable password, the attacker could additionally perform a password cracking attack to recover the account password for further malicious use.

Local Image Disclosure Via Linked Images

Similar to the previous case, processing a document with a reference to a local image file will result in that file being included in the final document. This can lead to sensitive information disclosure.

Denial of Service

An attacker could upload a document that either referenced or included extremely large images – the so-called “decompression bombs”. When processing these images, the library will consume huge amounts of memory and CPU time.

Server-Side Request Forgery Via Linked Content

An attacker could create a series of documents containing embedded links to common combinations of internal IP address and port, then submit them to a web service using the Aspose.Words library to process the documents.

Based on the length of time the service uses to process the document, the attacker could determine if a given IP/Port combination is filtered by a firewall:

  • longer processing time indicates that the TCP SYN packet sent by the server was dropped by a firewall
  • quick processing time indicates a successful connection has been made

Solutions of Security Issues

To solve the problems described above and to improve the security of web applications, you can control or disable loading of external resources using IResourceLoadingCallback.

The following code example shows how to disable external images loading:

C++

class DisableExternalImagesHandler : public IResourceLoadingCallback
{
public:
	ResourceLoadingAction ResourceLoading(System::SharedPtr<ResourceLoadingArgs> args) override
	{
		// Skip external images loading.
		return args->get_ResourceType() == ResourceType::Image
			? ResourceLoadingAction::Skip
			: ResourceLoadingAction::Default;
		}
};

void LoadDocument(const System::String& documentFilename)
{
	auto disableExternalImagesHandler = System::MakeObject<LoadOptions>();

disableExternalImagesHandler->set_ResourceLoadingCallback(System::MakeObject<DisableExternalImagesHandler>());

	auto doc = System::MakeObject<Document>(documentFilename, disableExternalImagesHandler);
}

The following code example shows how to disable remote resources:

C++

class DisableRemoteResourcesHandler : public IResourceLoadingCallback
{
	static bool IsLocalResource(const System::String& originalUri)
	{
		// CodePorting.CsToCpp.Native.API can handle only absolute uri
		auto uri = System::MakeObject<System::Uri>(originalUri);
		if (uri->get_IsAbsoluteUri())
		{
			return uri->get_Scheme().Equals(u"file", System::StringComparison::OrdinalIgnoreCase);
		}

		return false;
	}
public:
	ResourceLoadingAction ResourceLoading(System::SharedPtr<ResourceLoadingArgs> args) override
	{
		return IsLocalResource(args->get_OriginalUri())
			? ResourceLoadingAction::Default
			: ResourceLoadingAction::Skip;
	}
};

void LoadDocument(const System::String& documentFilename)
{
	auto disableRemoteResourcesHandler = System::MakeObject<LoadOptions>();

disableRemoteResourcesHandler->set_ResourceLoadingCallback(System::MakeObject<DisableRemoteResourcesHandler>());

	auto doc = System::MakeObject<Document>(documentFilename, disableRemoteResourcesHandler);
}


FAQ

  1. Q: How can I stop Aspose.Words for C++ from loading external images?
    A: Implement a custom class that inherits from IResourceLoadingCallback and return ResourceLoadingAction::Skip when args->get_ResourceType() equals ResourceType::Image. Register the handler via LoadOptions::set_ResourceLoadingCallback before loading the document.

  2. Q: I want to allow only local files but block any remote HTTP/HTTPS resources. How do I achieve this?
    A: In your IResourceLoadingCallback implementation, examine args->get_OriginalUri(). If the URI scheme is "file" (or the path is a UNC/local file), return ResourceLoadingAction::Default; otherwise return ResourceLoadingAction::Skip. This lets local resources load while remote ones are ignored.

  3. Q: Will disabling external resource loading affect the visual layout of the document?
    A: Yes. Images, CSS, or linked HTML that are skipped will not appear in the rendered document, which may alter layout or cause missing placeholders. Test your templates after disabling loading to ensure the final appearance meets expectations.

  4. Q: How can I detect when a document attempts to load a remote resource without actually loading it?
    A: Inside ResourceLoading, you can log or collect the args->get_OriginalUri() before deciding to skip. This lets you audit which external resources the document references while keeping them from being fetched.

  5. Q: Can I apply different resource‑loading policies to different documents in the same application?
    A: Yes. Create a separate LoadOptions instance for each document, assign the appropriate IResourceLoadingCallback implementation, and pass the options to the Document constructor. This isolates the settings per document.