GHSA-8J5Q-MFJ2-5Q9Q

Vulnerability from github – Published: 2026-07-20 23:21 – Updated: 2026-07-20 23:21
VLAI
Summary
@astrojs/rss: XML Injection via Unescaped RSS Feed Fields
Details

Summary

In @astrojs/rss, the source.title and enclosure.type item fields are interpolated directly into XML template strings without XML-character escaping before being parsed by fast-xml-parser. An attacker who controls these field values can inject arbitrary XML elements into the generated RSS feed.

Details

Two fields in packages/astro-rss/src/index.ts are affected:

source.title

item.source = parser.parse(
  `<source url="${result.source.url}">${result.source.title}</source>`,
).source;

source.title is validated only as z.string(), with no restriction on XML special characters. A value containing </source> followed by arbitrary XML is parsed as real XML elements, merging injected nodes into the RSS item.

enclosure.type

item.enclosure = parser.parse(
  `<enclosure url="${enclosureURL}" length="${result.enclosure.length}" type="${result.enclosure.type}"/>`,
).enclosure;

enclosure.type is also z.string() and is interpolated into an XML attribute without escaping. A value containing " followed by additional XML can break out of the attribute and inject extra elements.

Proof of Concept

source.title injection:

source: {
  url: 'https://legit.example.com',
  title: '</source><item><title>INJECTED</title><link>https://evil.com</link></item><source>',
}
// Result: RSS feed contains an injected <item> element with an evil.com link

enclosure.type injection:

enclosure: {
  url: 'https://example.com/a.mp3',
  length: 0,
  type: 'audio/mpeg" /><link>https://evil.example.com</link><enclosure fake="',
}
// Result: RSS feed contains an injected <link> element

Both injections were confirmed with fast-xml-parser: the injected "link": "https://evil.com" appears in the parsed output.

Impact

An attacker who can control source.title or enclosure.type values (e.g., via a CMS, database, or user-submitted content that populates RSSFeedItem) can inject arbitrary XML into the generated RSS feed. This corrupts feed structure, injects false metadata (e.g., a fake <link> pointing to a malicious URL), and can cause feed readers to misparse or display attacker-controlled content. In SSR mode (output: 'server'), the poisoned feed is served on every request to all subscribers.

Patches

Fixed in @astrojs/rss@4.0.19.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "@astrojs/rss"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.0.0"
            },
            {
              "fixed": "4.0.19"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-59728"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-91"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-20T23:21:47Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "## Summary\n\nIn `@astrojs/rss`, the `source.title` and `enclosure.type` item fields are interpolated directly into XML template strings without XML-character escaping before being parsed by `fast-xml-parser`. An attacker who controls these field values can inject arbitrary XML elements into the generated RSS feed.\n\n## Details\n\nTwo fields in `packages/astro-rss/src/index.ts` are affected:\n\n### `source.title`\n\n```typescript\nitem.source = parser.parse(\n  `\u003csource url=\"${result.source.url}\"\u003e${result.source.title}\u003c/source\u003e`,\n).source;\n```\n\n`source.title` is validated only as `z.string()`, with no restriction on XML special characters. A value containing `\u003c/source\u003e` followed by arbitrary XML is parsed as real XML elements, merging injected nodes into the RSS item.\n\n### `enclosure.type`\n\n```typescript\nitem.enclosure = parser.parse(\n  `\u003cenclosure url=\"${enclosureURL}\" length=\"${result.enclosure.length}\" type=\"${result.enclosure.type}\"/\u003e`,\n).enclosure;\n```\n\n`enclosure.type` is also `z.string()` and is interpolated into an XML attribute without escaping. A value containing `\"` followed by additional XML can break out of the attribute and inject extra elements.\n\n## Proof of Concept\n\n`source.title` injection:\n\n```javascript\nsource: {\n  url: \u0027https://legit.example.com\u0027,\n  title: \u0027\u003c/source\u003e\u003citem\u003e\u003ctitle\u003eINJECTED\u003c/title\u003e\u003clink\u003ehttps://evil.com\u003c/link\u003e\u003c/item\u003e\u003csource\u003e\u0027,\n}\n// Result: RSS feed contains an injected \u003citem\u003e element with an evil.com link\n```\n\n`enclosure.type` injection:\n\n```javascript\nenclosure: {\n  url: \u0027https://example.com/a.mp3\u0027,\n  length: 0,\n  type: \u0027audio/mpeg\" /\u003e\u003clink\u003ehttps://evil.example.com\u003c/link\u003e\u003cenclosure fake=\"\u0027,\n}\n// Result: RSS feed contains an injected \u003clink\u003e element\n```\n\nBoth injections were confirmed with `fast-xml-parser`: the injected `\"link\": \"https://evil.com\"` appears in the parsed output.\n\n## Impact\n\nAn attacker who can control `source.title` or `enclosure.type` values (e.g., via a CMS, database, or user-submitted content that populates `RSSFeedItem`) can inject arbitrary XML into the generated RSS feed. This corrupts feed structure, injects false metadata (e.g., a fake `\u003clink\u003e` pointing to a malicious URL), and can cause feed readers to misparse or display attacker-controlled content. In SSR mode (`output: \u0027server\u0027`), the poisoned feed is served on every request to all subscribers.\n\n## Patches\n\nFixed in `@astrojs/rss@4.0.19`.",
  "id": "GHSA-8j5q-mfj2-5q9q",
  "modified": "2026-07-20T23:21:47Z",
  "published": "2026-07-20T23:21:47Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/withastro/astro/security/advisories/GHSA-8j5q-mfj2-5q9q"
    },
    {
      "type": "WEB",
      "url": "https://github.com/withastro/astro/pull/17209"
    },
    {
      "type": "WEB",
      "url": "https://github.com/withastro/astro/commit/fbcfa039dfe3d700b239f595a6c55ee35e45bd06"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/withastro/astro"
    },
    {
      "type": "WEB",
      "url": "https://github.com/withastro/astro/releases/tag/@astrojs/rss@4.0.19"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "@astrojs/rss: XML Injection via Unescaped RSS Feed Fields"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…

Loading…