Skip to content

Commit cfe62ac

Browse files
1 parent 583d924 commit cfe62ac

File tree

4 files changed

+83
-5
lines changed

4 files changed

+83
-5
lines changed

advisories/github-reviewed/2026/03/GHSA-9q36-67vc-rrwg/GHSA-9q36-67vc-rrwg.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-9q36-67vc-rrwg",
4-
"modified": "2026-03-09T19:54:54Z",
4+
"modified": "2026-03-23T21:49:25Z",
55
"published": "2026-03-09T19:54:54Z",
6-
"aliases": [],
6+
"aliases": [
7+
"CVE-2026-27646"
8+
],
79
"summary": "OpenClaw: Sandboxed /acp spawn requests could initialize host ACP sessions",
810
"details": "### Summary\nSandboxed requester sessions could reach host-side ACP session initialization through `/acp spawn`.\n\nOpenClaw already blocked `sessions_spawn({ runtime: \"acp\" })` from sandboxed sessions, but the slash-command path initialized ACP directly without applying the same host-runtime guard first.\n\n### Affected Packages / Versions\n- npm package: `openclaw`\n- Affected versions: `<= 2026.3.2`\n- Patched version: `>= 2026.3.7`\n\n### Details\nACP sessions run on the host, not inside the OpenClaw sandbox. The direct ACP spawn path in `src/agents/acp-spawn.ts` already denied sandboxed requesters, but `/acp spawn` in `src/auto-reply/reply/commands-acp/lifecycle.ts` called `initializeSession(...)` without first applying the same restriction.\n\nIn affected versions, an already authorized sender in a sandboxed session could use `/acp spawn` to cross from sandboxed chat context into host-side ACP runtime initialization when ACP was enabled and a backend was available.\n\n### Fix Commit(s)\n- `61000b8e4ded919ca1a825d4700db4cb3fdc56e3`\n\n### Fix Details\nThe fix introduced a shared ACP runtime-policy guard in `src/agents/acp-spawn.ts` and reused it from the `/acp spawn` handler in `src/auto-reply/reply/commands-acp/lifecycle.ts` before any ACP backend initialization. Regression coverage was added in `src/auto-reply/reply/commands-acp.test.ts` to prove sandboxed `/acp spawn` requests are rejected early, while existing ACP spawn behavior for non-sandboxed sessions remains unchanged.\n\n### Release Process Note\nPatched version is pre-set to `2026.3.7` so the advisory can be published once that npm release is available.\n\nThanks @tdjackey for reporting.",
911
"severity": [
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-fp4x-ggrf-wmc6",
4+
"modified": "2026-03-23T21:48:24Z",
5+
"published": "2026-03-23T21:48:24Z",
6+
"aliases": [],
7+
"summary": "H3 has an Open Redirect via Protocol-Relative Path in redirectBack() Referer Validation",
8+
"details": "## Summary\n\nThe `redirectBack()` utility in h3 validates that the `Referer` header shares the same origin as the request before using its pathname as the redirect `Location`. However, the pathname is not sanitized for protocol-relative paths (starting with `//`). An attacker can craft a same-origin URL with a double-slash path segment that passes the origin check but produces a `Location` header interpreted by browsers as a protocol-relative redirect to an external domain.\n\n## Details\n\nThe vulnerable code is in `src/utils/response.ts:89-97`:\n\n```typescript\nexport function redirectBack(\n event: H3Event,\n opts: { fallback?: string; status?: number; allowQuery?: boolean } = {},\n): HTTPResponse {\n const referer = event.req.headers.get(\"referer\");\n let location = opts.fallback ?? \"/\";\n if (referer && URL.canParse(referer)) {\n const refererURL = new URL(referer);\n if (refererURL.origin === event.url.origin) {\n // BUG: pathname can be \"//evil.com/path\" which browsers interpret\n // as a protocol-relative URL\n location = refererURL.pathname + (opts.allowQuery ? refererURL.search : \"\");\n }\n }\n return redirect(location, opts.status);\n}\n```\n\nThe root cause is a discrepancy between how the WHATWG URL parser and browsers handle double-slash paths:\n\n1. `new URL(\"http://target.com//evil.com/path\").origin` → `\"http://target.com\"` — origin check **passes**\n2. `new URL(\"http://target.com//evil.com/path\").pathname` → `\"//evil.com/path\"` — extracted as redirect location\n3. Browser receives `Location: //evil.com/path` → interprets as protocol-relative URL → **redirects to `evil.com`**\n\n**Attack scenario:** The attacker shares a link like `http://target.com//evil.com/page`. If the target application has catch-all routes (common in SPAs built with h3/Nitro), the app serves its page at that URL. When the user navigates to an endpoint calling `redirectBack()`, the browser sends `Referer: http://target.com//evil.com/page`. The origin check passes, and the user is redirected to `evil.com`, which can host a phishing page mimicking the target.\n\n## PoC\n\n```bash\n# 1. Create a minimal h3 app with redirectBack\ncat > /tmp/h3-redirect-poc.ts << 'SCRIPT'\nimport { H3, redirectBack } from \"h3\";\n\nconst app = new H3();\napp.post(\"/submit\", (event) => redirectBack(event));\n\nconst res = await app.fetch(new Request(\"http://localhost/submit\", {\n method: \"POST\",\n headers: { referer: \"http://localhost//evil.com/steal\" }\n}));\n\nconsole.log(\"Status:\", res.status);\nconsole.log(\"Location:\", res.headers.get(\"location\"));\n// Expected: a same-origin path\n// Actual: \"//evil.com/steal\" — protocol-relative redirect to evil.com\nSCRIPT\n\n# 2. Verify URL parsing behavior\nnode -e \"\nconst u = new URL('http://localhost//evil.com/steal');\nconsole.log('origin:', u.origin); // http://localhost\nconsole.log('pathname:', u.pathname); // //evil.com/steal\nconsole.log('origin matches localhost:', u.origin === 'http://localhost'); // true\n\"\n# Output:\n# origin: http://localhost\n# pathname: //evil.com/steal\n# origin matches localhost: true\n```\n\n## Impact\n\nAn attacker can redirect users from a trusted application to an attacker-controlled domain. This enables:\n\n- **Credential phishing**: Redirect to a lookalike login page to harvest credentials\n- **OAuth token theft**: In OAuth flows using `redirectBack()`, steal authorization codes by redirecting to an attacker's callback\n- **Trust exploitation**: Users see the initial link points to the trusted domain, lowering suspicion\n\nThe vulnerability requires no authentication and affects any endpoint using `redirectBack()`.\n\n## Recommended Fix\n\nSanitize the extracted pathname to prevent protocol-relative URLs. In `src/utils/response.ts`, after extracting the pathname from the referer:\n\n```typescript\nexport function redirectBack(\n event: H3Event,\n opts: { fallback?: string; status?: number; allowQuery?: boolean } = {},\n): HTTPResponse {\n const referer = event.req.headers.get(\"referer\");\n let location = opts.fallback ?? \"/\";\n if (referer && URL.canParse(referer)) {\n const refererURL = new URL(referer);\n if (refererURL.origin === event.url.origin) {\n let pathname = refererURL.pathname;\n // Prevent protocol-relative open redirect (e.g., \"//evil.com\")\n if (pathname.startsWith(\"//\")) {\n pathname = \"/\" + pathname.replace(/^\\/+/, \"\");\n }\n location = pathname + (opts.allowQuery ? refererURL.search : \"\");\n }\n }\n return redirect(location, opts.status);\n}\n```",
9+
"severity": [
10+
{
11+
"type": "CVSS_V3",
12+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N"
13+
}
14+
],
15+
"affected": [
16+
{
17+
"package": {
18+
"ecosystem": "npm",
19+
"name": "h3"
20+
},
21+
"ranges": [
22+
{
23+
"type": "ECOSYSTEM",
24+
"events": [
25+
{
26+
"introduced": "2.0.1-rc.17"
27+
},
28+
{
29+
"fixed": "2.0.1-rc.18"
30+
}
31+
]
32+
}
33+
],
34+
"versions": [
35+
"2.0.1-rc.17"
36+
]
37+
}
38+
],
39+
"references": [
40+
{
41+
"type": "WEB",
42+
"url": "https://github.com/h3js/h3/security/advisories/GHSA-fp4x-ggrf-wmc6"
43+
},
44+
{
45+
"type": "WEB",
46+
"url": "https://github.com/h3js/h3/commit/459a1c6593365b0810e9c502df7c3e82837321d7"
47+
},
48+
{
49+
"type": "PACKAGE",
50+
"url": "https://github.com/h3js/h3"
51+
},
52+
{
53+
"type": "WEB",
54+
"url": "https://github.com/h3js/h3/releases/tag/v2.0.1-rc.18"
55+
}
56+
],
57+
"database_specific": {
58+
"cwe_ids": [
59+
"CWE-601"
60+
],
61+
"severity": "MODERATE",
62+
"github_reviewed": true,
63+
"github_reviewed_at": "2026-03-23T21:48:24Z",
64+
"nvd_published_at": null
65+
}
66+
}

advisories/github-reviewed/2026/03/GHSA-q5pr-72pq-83v3/GHSA-q5pr-72pq-83v3.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-q5pr-72pq-83v3",
4-
"modified": "2026-03-23T21:44:55Z",
4+
"modified": "2026-03-23T21:49:19Z",
55
"published": "2026-03-23T21:44:55Z",
66
"aliases": [],
77
"summary": "H3: Unbounded Chunked Cookie Count in Session Cleanup Loop may Lead to Denial of Service",
@@ -38,9 +38,17 @@
3838
"type": "WEB",
3939
"url": "https://github.com/h3js/h3/security/advisories/GHSA-q5pr-72pq-83v3"
4040
},
41+
{
42+
"type": "WEB",
43+
"url": "https://github.com/h3js/h3/commit/399257cb406fbeda313d88c1e288a15124fc82af"
44+
},
4145
{
4246
"type": "PACKAGE",
4347
"url": "https://github.com/h3js/h3"
48+
},
49+
{
50+
"type": "WEB",
51+
"url": "https://github.com/h3js/h3/releases/tag/v2.0.1-rc.18"
4452
}
4553
],
4654
"database_specific": {

advisories/github-reviewed/2026/03/GHSA-r6qf-8968-wj9q/GHSA-r6qf-8968-wj9q.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-r6qf-8968-wj9q",
4-
"modified": "2026-03-09T19:54:25Z",
4+
"modified": "2026-03-23T21:49:07Z",
55
"published": "2026-03-09T19:54:25Z",
6-
"aliases": [],
6+
"aliases": [
7+
"CVE-2026-27183"
8+
],
79
"summary": "OpenClaw: system.run wrapper-depth boundary could skip shell approval gating",
810
"details": "OpenClaw's `system.run` dispatch-wrapper handling applied different depth-boundary rules to shell-wrapper approval detection and execution planning.\n\nWith exactly four transparent dispatch wrappers such as repeated `env` invocations before `/bin/sh -c`, the approval classifier could stop treating the command as a shell wrapper at the depth boundary while execution planning still unwrapped through to the shell payload. In `security=allowlist` mode, that mismatch could skip the expected approval-required path for the shell wrapper invocation.\n\nLatest published npm version: `2026.3.2`\n\nFixed on `main` on March 7, 2026 in `2fc95a7cfc1eb9306356510b0251b6d51fb1c0b0` by keeping shell-wrapper classification active at the configured dispatch depth boundary and only failing closed beyond that boundary. This aligns approval gating with the execution plan. Legitimate shallow dispatch-wrapper usage continues to work.\n\n## Affected Packages / Versions\n\n- Package: `openclaw` (npm)\n- Affected versions: `<= 2026.3.2`\n- Patched version: `>= 2026.3.7`\n\n## Fix Commit(s)\n\n- `2fc95a7cfc1eb9306356510b0251b6d51fb1c0b0`\n\n## Release Process Note\n\nnpm `2026.3.7` was published on March 8, 2026. This advisory is fixed in the released package.\n\nThanks @tdjackey for reporting.",
911
"severity": [

0 commit comments

Comments
 (0)