Repository navigation
Resource Security
Starting with Ironpress 1.5.1, every document resource passes through one conversion-owned loader. This includes fonts and all supported image forms.
The loader keeps three decisions independent:
- HTML sanitization controls active or dangerous markup.
- The local-file policy controls which directory can be read.
- The network policy controls HTTP and HTTPS requests.
Disabling one control does not disable the other two.
remote remains disabled by default. Without it:
- No HTTP or HTTPS request is made.
- The optional HTTP, URL, and IP-classification dependencies are not compiled.
- HTML, Markdown, inline
data:images, and custom font bytes work normally. - Local document assets work when
base_pathorresource_rootauthorizes them.
There is no network runtime cost for applications that do not enable the feature.
Local files are denied until a directory is explicitly authorized:
use ironpress::HtmlConverter;
use std::path::Path;
let pdf = HtmlConverter::new()
.base_path(Path::new("./invoice-assets"))
.convert("<img src='logo.png'>")
.expect("conversion succeeds");base_path is both the URL base and the authorization boundary. Use
resource_root when a document needs assets from a broader ancestor directory.
Traversal and symlink escapes outside the canonical root are denied.
Before 1.5.1, .sanitize(false) could implicitly allow document paths relative
to the process working directory. That coupling was unsafe and is removed.
If an application relied on it, keep the intended behavior explicitly:
use std::path::Path;
let pdf = HtmlConverter::new()
.sanitize(false)
.base_path(Path::new("./invoice-assets"))
.convert("<img src='logo.png'>")
.expect("conversion succeeds");This is the only expected behavior change for users who do not enable remote.
Enable remote loading explicitly:
ironpress = { version = "1.5.1", features = ["remote"] }The default policy:
- Allows only HTTP and HTTPS.
- Allows public destinations.
- Denies loopback, private, link-local, metadata, multicast, documentation, and reserved addresses.
- Rechecks every redirect, up to eight redirects.
- Pins approved DNS results to the connection.
- Limits each response body to 10 MB.
These rules cover fonts, <img>, generated content, list markers, backgrounds,
border images, nested SVG images, and masks.
Use an allow list together with public-IP denial to restrict downloads to a known host:
use ironpress::{HtmlConverter, NetworkPolicy, RemoteHost};
let cdn: RemoteHost = "cdn.example.com".parse().expect("valid host");
let policy = NetworkPolicy::default()
.with_allow_list([cdn])
.deny_public_ips(true)
.max_redirects(4)
.max_body_size(2 * 1024 * 1024);
let pdf = HtmlConverter::new()
.network_policy(policy)
.convert("<img src='https://cdn.example.com/logo.png'>")
.expect("conversion succeeds");An allow entry explicitly trusts its host and bypasses the IP-class check. A
deny entry always wins. A .example.com entry matches subdomains but not the
apex host.
To reach an intentional private service, prefer an exact allow entry instead of disabling private-address protection globally.
Ironpress respects environment proxy configuration. The proxy is trusted operator configuration, not document input.
Host allow and deny lists still apply to the target URL. If the proxy resolves the target hostname, the proxy must enforce the final destination IP policy. Ironpress cannot inspect a network hop that only the proxy can see.
Library checks are one layer, not the whole server boundary. A service that converts untrusted documents should also:
- Block cloud metadata, loopback, private, and link-local networks outside the process.
- Restrict outbound DNS and traffic to required hosts or a controlled proxy.
- Apply conversion time, memory, and process limits.
- Scan uploaded or downloaded images when the product threat model requires it.
Ironpress controls whether a resource may be accessed. It does not determine whether an allowed image contains malware.