GHSA-7Q9X-8G6P-3X75
Vulnerability from github – Published: 2026-03-25 17:15 – Updated: 2026-03-25 17:15Impact
The renderPairingPage() function embeds the error parameter directly into HTML without escaping:
const errorHtml = error ? `<p style="color:#e74c3c">${error}</p>` : "";
All current call sites pass hardcoded strings, so this is not exploitable today. However, the function is architecturally fragile — if a future code change passes user-controlled or dynamic content into the error parameter, it would create an XSS vulnerability.
The renderAuthorizePage() function in the same file correctly uses escapeHtml() for dynamic content, making this an inconsistency.
Affected code:
- packages/server/src/index.ts:64-89 — renderPairingPage() with unescaped error interpolation
- Compare: packages/server/src/index.ts:130 — renderAuthorizePage() correctly uses escapeHtml()
Patches
v0.70.1
Fix: Apply escapeHtml() to the error parameter:
const errorHtml = error ? `<p style="color:#e74c3c">${escapeHtml(error)}</p>` : "";
Workarounds
No workaround needed — all current callers pass hardcoded strings.
Resources
- CWE-79: Improper Neutralization of Input During Web Page Generation
- File:
packages/server/src/index.ts
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.70.0"
},
"package": {
"ecosystem": "npm",
"name": "@grackle-ai/server"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.70.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-79"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-25T17:15:40Z",
"nvd_published_at": null,
"severity": "LOW"
},
"details": "### Impact\n\nThe `renderPairingPage()` function embeds the `error` parameter directly into HTML without escaping:\n```typescript\nconst errorHtml = error ? `\u003cp style=\"color:#e74c3c\"\u003e${error}\u003c/p\u003e` : \"\";\n```\n\nAll current call sites pass hardcoded strings, so this is **not exploitable today**. However, the function is architecturally fragile \u2014 if a future code change passes user-controlled or dynamic content into the error parameter, it would create an XSS vulnerability.\n\nThe `renderAuthorizePage()` function in the same file correctly uses `escapeHtml()` for dynamic content, making this an inconsistency.\n\n**Affected code:**\n- `packages/server/src/index.ts:64-89` \u2014 `renderPairingPage()` with unescaped error interpolation\n- Compare: `packages/server/src/index.ts:130` \u2014 `renderAuthorizePage()` correctly uses `escapeHtml()`\n\n### Patches\n\nv0.70.1\n\n**Fix:** Apply `escapeHtml()` to the error parameter:\n```typescript\nconst errorHtml = error ? `\u003cp style=\"color:#e74c3c\"\u003e${escapeHtml(error)}\u003c/p\u003e` : \"\";\n```\n\n### Workarounds\n\nNo workaround needed \u2014 all current callers pass hardcoded strings.\n\n### Resources\n\n- CWE-79: Improper Neutralization of Input During Web Page Generation\n- File: `packages/server/src/index.ts`",
"id": "GHSA-7q9x-8g6p-3x75",
"modified": "2026-03-25T17:15:40Z",
"published": "2026-03-25T17:15:40Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/nick-pape/grackle/security/advisories/GHSA-7q9x-8g6p-3x75"
},
{
"type": "PACKAGE",
"url": "https://github.com/nick-pape/grackle"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N",
"type": "CVSS_V4"
}
],
"summary": "@grackle-ai/server: Unescaped Error String in renderPairingPage() HTML Template"
}
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.