VYPR
Low severity3.1OSV Advisory· Published Jul 15, 2024· Updated Apr 15, 2026

CVE-2024-39919

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.

PackageAffected versionsPatched versions
@jmondi/url-to-pngnpm
< 2.1.22.1.2

Affected products

1

Patches

1
f62ff40403ff

block list

https://github.com/jasonraimondi/url-to-pngNishant JainJul 12, 2024via ghsa
5 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

4

News mentions

0

No linked articles in our index yet.