Every CVESearch/Get API key

GHSA-89v5-38xr-9m4j

Postiz has Multiple SSRF Vectors - Webhooks, RSS Feed, URL Loader

7.8 High

GHSA-89v5-38xr-9m4j is a high vulnerability (CVSS 7.8) in postiz, published March 27, 2026. No source lists public exploit code. No source names a fixed version.

What does this mean?
Severity
7.8 HighCVSS 4.0, GitHub Advisories
Exploit chance
UnscoredNo EPSS score yet
Exploitation
None knownNot on CISA’s or ENISA’s lists
Fixed in
No fix listedNo source names one

Description

Summary

Postiz has multiple SSRF vulnerabilities where user-provided URLs are fetched server-side without any IP validation or SSRF protection.

Vulnerable Code

1. Webhook Send Endpoint (Most Critical)

apps/backend/src/api/routes/webhooks.controller.ts lines 58-70:

async sendWebhook(@Body() body: any, @Query('url') url: string) {
  try {
    await fetch(url, {  // No URL validation
      method: 'POST',
      body: JSON.stringify(body),
      headers: { 'Content-Type': 'application/json' },
    });
  } catch (err) { }
  return { send: true };
}

Accepts arbitrary URL via query parameter and fetches directly.

2. Stored Webhook Delivery

apps/orchestrator/src/activities/post.activity.ts lines 256-281:

async sendWebhooks(postId: string, orgId: string, integrationId: string) {
  const webhooks = await this._webhookService.getWebhooks(orgId);
  return Promise.all(
    webhooks.map(async (webhook) => {
      await fetch(webhook.url, {  // Stored URL, no validation
        method: 'POST',
        body: JSON.stringify(post),
      });
    })
  );
}

3. RSS/XML Feed Parser

libraries/nestjs-libraries/src/database/prisma/autopost/autopost.service.ts line 135:

async loadXML(url: string) {
  const { items } = await parser.parseURL(url);  // No URL validation
}

4. HTML Content Loader

libraries/nestjs-libraries/src/database/prisma/autopost/autopost.service.ts line 185:

async loadUrl(url: string) {
  const loadDom = new JSDOM(await (await fetch(url)).text());  // No validation
}

Missing Protections

  • No request-filtering-agent or SSRF library
  • No private IP range filtering
  • No cloud metadata endpoint blocking
  • No DNS rebinding protection
  • URL validation only via @IsUrl() decorator (format only, no IP check)

Attack Scenarios

  1. POST /webhooks/send?url=http://169.254.169.254/latest/meta-data/ → AWS metadata theft
  2. POST /autopost/send?url=http://127.0.0.1:6379 → Internal Redis access
  3. Create webhook with http://10.0.0.1:8080/admin → Internal service access on post publish

Impact

  • Cloud metadata theft: AWS/GCP/Azure credentials
  • Internal network scanning: Full access to private IP ranges
  • Multiple entry points: Webhooks, RSS feeds, URL loader all vulnerable

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
Low
Integrity
Low
Availability
None

Affected packages

Affected packages
PackageAffectedFixed
postiz
npm
through 2.0.12None known

What each source reports

GitHub Advisories Score used7.8

Postiz has Multiple SSRF Vectors - Webhooks, RSS Feed, URL Loader

Summary

Postiz has multiple SSRF vulnerabilities where user-provided URLs are fetched server-side without any IP validation or SSRF protection.

Vulnerable Code

1. Webhook Send Endpoint (Most Critical)

apps/backend/src/api/routes/webhooks.controller.ts lines 58-70:

async sendWebhook(@Body() body: any, @Query('url') url: string) {
  try {
    await fetch(url, {  // No URL validation
      method: 'POST',
      body: JSON.stringify(body),
      headers: { 'Content-Type': 'application/json' },
    });
  } catch (err) { }
  return { send: true };
}

Accepts arbitrary URL via query parameter and fetches directly.

2. Stored Webhook Delivery

apps/orchestrator/src/activities/post.activity.ts lines 256-281:

async sendWebhooks(postId: string, orgId: string, integrationId: string) {
  const webhooks = await this._webhookService.getWebhooks(orgId);
  return Promise.all(
    webhooks.map(async (webhook) => {
      await fetch(webhook.url, {  // Stored URL, no validation
        method: 'POST',
        body: JSON.stringify(post),
      });
    })
  );
}

3. RSS/XML Feed Parser

libraries/nestjs-libraries/src/database/prisma/autopost/autopost.service.ts line 135:

async loadXML(url: string) {
  const { items } = await parser.parseURL(url);  // No URL validation
}

4. HTML Content Loader

libraries/nestjs-libraries/src/database/prisma/autopost/autopost.service.ts line 185:

async loadUrl(url: string) {
  const loadDom = new JSDOM(await (await fetch(url)).text());  // No validation
}

Missing Protections

  • No request-filtering-agent or SSRF library
  • No private IP range filtering
  • No cloud metadata endpoint blocking
  • No DNS rebinding protection
  • URL validation only via @IsUrl() decorator (format only, no IP check)

Attack Scenarios

  1. POST /webhooks/send?url=http://169.254.169.254/latest/meta-data/ → AWS metadata theft
  2. POST /autopost/send?url=http://127.0.0.1:6379 → Internal Redis access
  3. Create webhook with http://10.0.0.1:8080/admin → Internal service access on post publish

Impact

  • Cloud metadata theft: AWS/GCP/Azure credentials
  • Internal network scanning: Full access to private IP ranges
  • Multiple entry points: Webhooks, RSS feeds, URL loader all vulnerable
Record
GHSA-89v5-38xr-9m4j
CVSS 4.0
7.8 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:H/SI:L/SA:N
Weakness
CWE-918
Updated
2026-11-02
OSV7.8

Postiz has Multiple SSRF Vectors - Webhooks, RSS Feed, URL Loader

Summary

Postiz has multiple SSRF vulnerabilities where user-provided URLs are fetched server-side without any IP validation or SSRF protection.

Vulnerable Code

1. Webhook Send Endpoint (Most Critical)

apps/backend/src/api/routes/webhooks.controller.ts lines 58-70:

async sendWebhook(@Body() body: any, @Query('url') url: string) {
  try {
    await fetch(url, {  // No URL validation
      method: 'POST',
      body: JSON.stringify(body),
      headers: { 'Content-Type': 'application/json' },
    });
  } catch (err) { }
  return { send: true };
}

Accepts arbitrary URL via query parameter and fetches directly.

2. Stored Webhook Delivery

apps/orchestrator/src/activities/post.activity.ts lines 256-281:

async sendWebhooks(postId: string, orgId: string, integrationId: string) {
  const webhooks = await this._webhookService.getWebhooks(orgId);
  return Promise.all(
    webhooks.map(async (webhook) => {
      await fetch(webhook.url, {  // Stored URL, no validation
        method: 'POST',
        body: JSON.stringify(post),
      });
    })
  );
}

3. RSS/XML Feed Parser

libraries/nestjs-libraries/src/database/prisma/autopost/autopost.service.ts line 135:

async loadXML(url: string) {
  const { items } = await parser.parseURL(url);  // No URL validation
}

4. HTML Content Loader

libraries/nestjs-libraries/src/database/prisma/autopost/autopost.service.ts line 185:

async loadUrl(url: string) {
  const loadDom = new JSDOM(await (await fetch(url)).text());  // No validation
}

Missing Protections

  • No request-filtering-agent or SSRF library
  • No private IP range filtering
  • No cloud metadata endpoint blocking
  • No DNS rebinding protection
  • URL validation only via @IsUrl() decorator (format only, no IP check)

Attack Scenarios

  1. POST /webhooks/send?url=http://169.254.169.254/latest/meta-data/ → AWS metadata theft
  2. POST /autopost/send?url=http://127.0.0.1:6379 → Internal Redis access
  3. Create webhook with http://10.0.0.1:8080/admin → Internal service access on post publish

Impact

  • Cloud metadata theft: AWS/GCP/Azure credentials
  • Internal network scanning: Full access to private IP ranges
  • Multiple entry points: Webhooks, RSS feeds, URL loader all vulnerable
Record
GHSA-89v5-38xr-9m4j
CVSS 4.0
7.8 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:H/SI:L/SA:N
Weakness
CWE-918
Updated
2026-11-02

History

History
RecordedChangedSources
first indexedGitHub Advisories, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

References

MoveEnter Open