CVE-2024-39919
Description
@jmondi/url-to-png is an open source URL to PNG utility featuring parallel rendering using Playwright for screenshots and with storage caching via Local, S3, or CouchDB. The package includes an ALLOW_LIST where the host can specify which services the user is permitted to capture screenshots of. By default, capturing screenshots of web services running on localhost, 127.0.0.1, or the [::] is allowed. If someone hosts this project on a server, users could then capture screenshots of other web services running locally. This issue has been addressed in version 2.1.1 with the addition of a blocklist. Users are advised to upgrade. There are no known workarounds for this vulnerability.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
@jmondi/url-to-pngnpm | < 2.1.2 | 2.1.2 |
Affected products
1- Range: 0.10.0, 0.10.1, 0.11.0, …
Patches
15 files changed · +38 −4
.env.sample+3 −0 modified@@ -10,6 +10,9 @@ NODE_ENV=development # Comma-separated list of allowed domains for screenshots (optional) #ALLOW_LIST=jasonraimondi.com,github.com +# Comma-separated list of allowed domains for screenshots (optional) +# BLOCK_LIST=example.com + # Cache-Control header value for the responses (optional) #CACHE_CONTROL="public, max-age=86400, immutable"
src/app.ts+9 −2 modified@@ -8,8 +8,9 @@ import { ImageRenderInterface } from "./lib/image_render.js"; import { logger } from "./lib/logger.js"; import { PlainConfigSchema } from "./lib/schema.js"; import { ImageStorage } from "./lib/storage/_base.js"; -import { formatAllowList } from "./lib/utils.js"; +import { formatUrlList } from "./lib/utils.js"; import { handleAllowListMiddleware } from "./middlewares/allow_list.js"; +import { handleBlockListMiddleware } from "./middlewares/block_list.js"; import { handleExtractQueryParamsMiddleware } from "./middlewares/extract_query_params.js"; import { getIndex } from "./routes/index.js"; @@ -57,8 +58,14 @@ export function createApplication( app.use("/", handleExtractQueryParamsMiddleware(stringEncrypter)); + if (process.env.BLOCK_LIST && process.env.BLOCK_LIST.trim() !== "") { + const allowList = formatUrlList(process.env.BLOCK_LIST); + logger.info(`Blocked Domains: ${allowList.join(", ")}`); + app.use("/", handleBlockListMiddleware(allowList)); + } + if (process.env.ALLOW_LIST && process.env.ALLOW_LIST.trim() !== "") { - const allowList = formatAllowList(process.env.ALLOW_LIST); + const allowList = formatUrlList(process.env.ALLOW_LIST); logger.info(`Allowed Domains: ${allowList.join(", ")}`); app.use("/", handleAllowListMiddleware(allowList)); }
src/lib/utils.ts+1 −1 modified@@ -1,4 +1,4 @@ -export function formatAllowList(allowList: string): string[] { +export function formatUrlList(allowList: string): string[] { return allowList.split(",").map(url => { url = url.trim().replace(/https?:\/\//g, ""); return new URL(`http://${url}`).host;
src/middlewares/allow_list.ts+3 −1 modified@@ -7,7 +7,9 @@ import { logger } from "../lib/logger.js"; export function handleAllowListMiddleware(allowList: string[]) { return async (c: Context<AppEnv>, next: () => Promise<void>) => { const input = c.get("input"); - const isValidDomain = allowList.includes(new URL(input.url).host); + const newurl = new URL(input.url).host; + logger.info(`URL new: ${newurl}`); + const isValidDomain = allowList.includes(newurl); if (!isValidDomain) { logger.warn(`Blocked request to ${input.url} - not in allowlist`);
src/middlewares/block_list.ts+22 −0 added@@ -0,0 +1,22 @@ +// blockedHostsMiddleware.ts +import { Context } from "hono"; +import { HTTPException } from "hono/http-exception"; + +import { AppEnv } from "../app.js"; +import { logger } from "../lib/logger.js"; + +export function handleBlockListMiddleware(blockList: string[]) { + return async (c: Context<AppEnv>, next: () => Promise<void>) => { + const input = c.get("input"); + const urlHost = new URL(input.url).host; + logger.info(`Request URL host: ${urlHost}`); + + // Check if the host is in the block list + if (blockList.includes(urlHost)) { + logger.warn(`Blocked request to ${input.url} - host is in block list`); + throw new HTTPException(403, { message: "Access to this URL is forbidden" }); + } + + await next(); + }; +}
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
4News mentions
0No linked articles in our index yet.