Skip to content

fix(gateway): block internal HTTP session overrides#55789

Open
RichardCao wants to merge 1 commit into
openclaw:mainfrom
RichardCao:fix/gateway-http-block-internal-session-override
Open

fix(gateway): block internal HTTP session overrides#55789
RichardCao wants to merge 1 commit into
openclaw:mainfrom
RichardCao:fix/gateway-http-block-internal-session-override

Conversation

@RichardCao

Copy link
Copy Markdown
Contributor

Summary

  • reject explicit x-openclaw-session-key overrides that target internal namespaces like subagent:, acp:, or cron:
  • return a 400 invalid_request_error from the OpenAI and OpenResponses HTTP endpoints instead of passing those keys into owner-trusted ingress
  • add request-context and endpoint coverage for the blocked overrides while preserving normal custom session keys

Testing

  • pnpm exec vitest run src/gateway/http-utils.request-context.test.ts src/gateway/openai-http.test.ts src/gateway/openresponses-http.test.ts

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: S labels Mar 27, 2026
@greptile-apps

greptile-apps Bot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a security guard that blocks x-openclaw-session-key header overrides targeting internal session namespaces (subagent:, acp:, cron:) in the OpenAI-compatible and OpenResponses HTTP endpoints, returning a 400 invalid_request_error instead of forwarding the key to the agent layer.\n\nKey changes:\n- http-utils.ts: Adds resolveReservedSessionKeyPrefix / normalizeReservedSessionKeyCandidate helpers that correctly handle both bare keys (subagent:worker) and agent:<id>: scoped keys (agent:main:subagent:worker) in a case-insensitive, whitespace-tolerant way; consistent with existing semantics in isSubagentSessionKey, isCronSessionKey, and isAcpSessionKey.\n- openai-http.ts / openresponses-http.ts: Both now wrap resolveGatewayRequestContext in a try/catch that serialises the thrown error as a 400 response, preventing the request from reaching the agent layer.\n- Tests added for each endpoint and the utility function; the only minor gap is that only the subagent: prefix is exercised — acp: and cron: have no dedicated test cases.\n- Note: tools-invoke-http.ts accepts a body-supplied sessionKey via a separate code path without the same reserved-prefix guard — this appears to be a pre-existing gap outside the stated scope of this PR and may warrant a follow-up.

Confidence Score: 5/5

Safe to merge; the guard logic is correct and consistent with existing session-key semantics, and both HTTP endpoints are protected.

The only open finding is a P2 test-coverage gap (missing acp: and cron: cases alongside the existing subagent: test), which does not affect correctness of the shipped guard. No P0 or P1 issues found.

src/gateway/http-utils.request-context.test.ts — missing acp: and cron: prefix test cases.

Important Files Changed

Filename Overview
src/gateway/http-utils.ts Adds resolveReservedSessionKeyPrefix / normalizeReservedSessionKeyCandidate helpers; throws from resolveSessionKey when a reserved prefix is matched.
src/gateway/openai-http.ts Wraps resolveGatewayRequestContext in try/catch; returns 400 invalid_request_error when the session key guard throws.
src/gateway/openresponses-http.ts Same try/catch guard as openai-http.ts applied to the OpenResponses handler.
src/gateway/http-utils.request-context.test.ts Adds a test for the subagent: prefix rejection path; acp: and cron: prefixes have no corresponding test cases.
src/gateway/openai-http.test.ts Adds an e2e block verifying 400 is returned for an internal subagent: session key and no agent command is dispatched.
src/gateway/openresponses-http.test.ts Adds equivalent e2e coverage for the OpenResponses endpoint.

Comments Outside Diff (1)

  1. src/gateway/http-utils.request-context.test.ts, line 46-57 (link)

    P2 Only subagent: prefix tested, acp: and cron: cases uncovered

    The new test exercises only the subagent: reserved prefix. RESERVED_SESSION_KEY_PREFIXES also includes acp: and cron:, but there are no cases that verify those are blocked. A future refactor that drops or misspells one of those entries would break silently.

    Consider adding additional it blocks (or parametrizing the existing one) to cover at least acp: and cron::

    // acp: prefix
    { "x-openclaw-session-key": "agent:main:acp:session" } → throws "...internal session namespace acp:"
    // cron: prefix
    { "x-openclaw-session-key": "agent:main:cron:daily" }  → throws "...internal session namespace cron:"
    // also test bare (non-agent-prefixed) variants e.g. "cron:daily"
    
    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/gateway/http-utils.request-context.test.ts
    Line: 46-57
    
    Comment:
    **Only `subagent:` prefix tested, `acp:` and `cron:` cases uncovered**
    
    The new test exercises only the `subagent:` reserved prefix. `RESERVED_SESSION_KEY_PREFIXES` also includes `acp:` and `cron:`, but there are no cases that verify those are blocked. A future refactor that drops or misspells one of those entries would break silently.
    
    Consider adding additional `it` blocks (or parametrizing the existing one) to cover at least `acp:` and `cron:`:
    
    ```
    // acp: prefix
    { "x-openclaw-session-key": "agent:main:acp:session" } → throws "...internal session namespace acp:"
    // cron: prefix
    { "x-openclaw-session-key": "agent:main:cron:daily" }  → throws "...internal session namespace cron:"
    // also test bare (non-agent-prefixed) variants e.g. "cron:daily"
    ```
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/gateway/http-utils.request-context.test.ts
Line: 46-57

Comment:
**Only `subagent:` prefix tested, `acp:` and `cron:` cases uncovered**

The new test exercises only the `subagent:` reserved prefix. `RESERVED_SESSION_KEY_PREFIXES` also includes `acp:` and `cron:`, but there are no cases that verify those are blocked. A future refactor that drops or misspells one of those entries would break silently.

Consider adding additional `it` blocks (or parametrizing the existing one) to cover at least `acp:` and `cron:`:

```
// acp: prefix
{ "x-openclaw-session-key": "agent:main:acp:session" } → throws "...internal session namespace acp:"
// cron: prefix
{ "x-openclaw-session-key": "agent:main:cron:daily" }  → throws "...internal session namespace cron:"
// also test bare (non-agent-prefixed) variants e.g. "cron:daily"
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(gateway): block internal HTTP sessio..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 14fd898273

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +450 to +453
sendJson(res, 400, {
error: {
message: err instanceof Error ? err.message : "Invalid session context.",
type: "invalid_request_error",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid exposing internal exceptions as client input errors

This catch now maps all resolveGatewayRequestContext failures to a 400 and returns err.message verbatim, but that context path calls resolveAgentIdForRequest() which reads config and can throw internal errors (for example loadConfig() throws detailed Invalid config at <path>... messages in src/config/io.ts). In that scenario, API callers receive server internals (filesystem path + validation details) as invalid_request_error, and a server-side failure is misclassified as a client error. Please only convert the reserved-session override failure to 400 and keep unexpected exceptions as generic 500s.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 825e21b. The reserved-prefix rejection now throws a dedicated GatewaySessionKeyOverrideError, and the OpenAI/OpenResponses handlers only translate that specific error to a 400 invalid_request_error. Unexpected context/config failures now fall through instead of leaking internal messages as client input errors.

@clawsweeper

clawsweeper Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 1, 2026, 8:36 AM ET / 12:36 UTC.

Summary
Review failed before ClawSweeper could summarize the requested change.

PR surface: Source +67, Tests +70. Total +137 across 6 files.

Reproducibility: unclear. The review failed before ClawSweeper could establish a reproduction path.

Review metrics: none identified.

Merge readiness
Overall: 🌊 off-meta tidepool
Proof: 🌊 off-meta tidepool
Patch quality: 🌊 off-meta tidepool
Result: rating does not apply to this item.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Risk before merge

  • [P1] No close action taken because the review did not complete.

Maintainer options:

  1. Decide the mitigation before merge
    Retry the Codex review after fixing the execution failure.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • [P1] Review did not complete, so no work-lane recommendation was made.
Review details

Best possible solution:

Retry the Codex review after fixing the execution failure.

Do we have a high-confidence way to reproduce the issue?

Unclear. The review failed before ClawSweeper could establish a reproduction path.

Is this the best way to solve the issue?

Unclear. Retry the review first so ClawSweeper can evaluate the actual issue and fix direction.

AGENTS.md: unclear because the file could not be read completely.

Codex review notes: model gpt-5.5, reasoning high; reviewed against ec2455a842cf.

Label changes

Label changes:

  • add rating: 🌊 off-meta tidepool: Overall readiness is 🌊 off-meta tidepool; proof is 🌊 off-meta tidepool and patch quality is 🌊 off-meta tidepool.
  • remove P2: Current review triage priority is none.
  • remove rating: 🦐 gold shrimp: Current PR rating is rating: 🌊 off-meta tidepool, so this older rating label is no longer current.
  • remove merge-risk: 🚨 compatibility: Current PR review selected no merge-risk labels.
  • remove status: 📣 needs proof: Current PR status no longer selects a status label.

Label justifications:

  • rating: 🌊 off-meta tidepool: Overall readiness is 🌊 off-meta tidepool; proof is 🌊 off-meta tidepool and patch quality is 🌊 off-meta tidepool.
Evidence reviewed

PR surface:

Source +67, Tests +70. Total +137 across 6 files.

View PR surface stats
Area Files Added Removed Net
Source 3 84 17 +67
Tests 3 70 0 +70
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 6 154 17 +137

What I checked:

  • failure reason: timeout.
  • codex failure detail: Codex review failed for this PR: spawnSync codex ETIMEDOUT.

Likely related people:

  • unknown: Codex failed before it could trace repository history. (role: review did not complete; confidence: low)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@RichardCao RichardCao force-pushed the fix/gateway-http-block-internal-session-override branch from 825e21b to e58b389 Compare April 30, 2026 05:41
@RichardCao

Copy link
Copy Markdown
Contributor Author

Refreshed this PR onto latest upstream/main (99950c7f1272dff6e2c34c2be45dfc5f89e62a60) and force-pushed the updated branch.

New head: e58b3893aee1fcece10a02f8ff24bde298b45ec5

What changed:

  • Rebuilt the original minimal fix on top of current main.
  • Rejects explicit x-openclaw-session-key overrides targeting internal namespaces over the OpenAI-compatible HTTP surfaces.
  • Covers subagent:, acp:, and cron: namespaces, including agent-scoped forms via parseAgentSessionKey.
  • Keeps error handling narrow: only GatewaySessionKeyOverrideError is mapped to HTTP 400; unexpected errors still surface through the normal server error path.

Review:

  • Fresh gpt-5.5 xhigh review found no important issues requiring changes before push.
  • Prior review feedback was considered:
    • Added acp: and cron: coverage alongside subagent: in http-utils.request-context.test.ts.
    • Kept the dedicated GatewaySessionKeyOverrideError so only invalid session override input maps to 400; unrelated context/config failures still surface through the normal server error path.
    • The noted tools-invoke-http.ts body-supplied sessionKey path was intentionally not folded into this PR to keep scope limited to OpenAI-compatible/OpenResponses header overrides. That separate HTTP ingress can be tracked as follow-up if maintainers want a broader all-HTTP policy.

Verification:

  • Passed: ./node_modules/.bin/vitest run --config test/vitest/vitest.gateway-core.config.ts src/gateway/http-utils.request-context.test.ts
  • Result: 1 file passed, 14 tests passed.
  • Blocked locally: src/gateway/openai-http.test.ts / src/gateway/openresponses-http.test.ts failed during import because this local node_modules is missing declared dependencies (typebox, global-agent). No endpoint assertions ran in those suites.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels May 19, 2026
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label May 19, 2026
@clawsweeper

clawsweeper Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat.

Where did the egg go?
  • The egg game starts only after the PR passes the real-behavior proof check.
  • Before that, no creature or rarity is rolled. The treat waits for real proof.
  • This is still just collectible flavor: proof affects review readiness, not creature quality.

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels May 24, 2026
@RichardCao RichardCao force-pushed the fix/gateway-http-block-internal-session-override branch from 9eaa1fa to 868a0c4 Compare June 1, 2026 12:24
@clawsweeper clawsweeper Bot added rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. size: S triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant