Skip to content

Policy: add gateway exposure checks#81981

Merged
giodl73-repo merged 3 commits into
openclaw:mainfrom
giodl73-repo:policy-gateway-exposure-conformance
May 22, 2026
Merged

Policy: add gateway exposure checks#81981
giodl73-repo merged 3 commits into
openclaw:mainfrom
giodl73-repo:policy-gateway-exposure-conformance

Conversation

@giodl73-repo

@giodl73-repo giodl73-repo commented May 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a Policy 1.0 Gateway exposure conformance category with config-only evidence and doctor/lint findings.

Logical base: #81974, now merged into main. This PR intentionally does not include runtime audit, gateway protocol, approval metadata, Swift protocol, or before-tool-call changes.

  • Records Gateway bind/auth/rate-limit/Control UI/Tailscale/remote/HTTP posture as policy evidence only when Gateway policy rules are configured.
  • Enforces non-loopback bind, disabled auth, missing explicit rate-limit posture, insecure Control UI toggles, Tailscale Funnel, remote mode, HTTP endpoints, and unrestricted URL-fetch posture.
  • Treats wildcard URL allowlists as unrestricted for gateway.http.requireUrlAllowlists.
  • Aligns custom bind exposure evidence with Gateway runtime validation: only canonical IPv4 custom hosts can count as active custom bind exposure; invalid or blank custom bind hosts are not treated as active exposure.
  • Documents the new Gateway policy rules and evidence shape.

Policy syntax

{
  "gateway": {
    "exposure": {
      "allowNonLoopbackBind": false,
      "allowTailscaleFunnel": false,
    },
    "auth": {
      "requireAuth": true,
      "requireExplicitRateLimit": true,
    },
    "controlUi": {
      "allowInsecure": false,
    },
    "remote": {
      "allow": false,
    },
    "http": {
      "denyEndpoints": ["chatCompletions", "responses"],
      "requireUrlAllowlists": true,
    },
  },
}

Safety

This is config-level conformance only. doctor --lint and policy checks read existing OpenClaw config and report findings. This PR does not launch a Gateway, mutate Gateway config, change Gateway runtime behavior, or add runtime enforcement.

Real behavior proof

Behavior addressed: adds policy conformance evidence and findings for Gateway exposure settings, including unsafe remote/custom binding, disabled auth, missing rate-limit posture, insecure Control UI toggles, remote gateway mode, enabled HTTP endpoints, and unrestricted URL-fetch posture.

Real environment tested: WSL Ubuntu checkout; PR head e7af8ffabd9f71c8d7ee84cc0749b97f1e5c7856 is signed and GitHub-verified.

Exact steps or command run after this patch:

  • pnpm docs:list
  • git diff --check
  • node scripts/run-vitest.mjs extensions/policy/src/doctor/register.test.ts extensions/policy/src/cli.test.ts -- --reporter=dot
  • pnpm deps:shrinkwrap:check
  • /mnt/c/src/claws-hapi/.agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --reviewer codex --fallback-reviewer none
  • /mnt/c/src/claws-hapi/.agents/skills/autoreview/scripts/autoreview --mode local --reviewer codex --fallback-reviewer none

Evidence after fix: docs index sanity completed; focused policy doctor/CLI tests passed 2 files and 117 tests after the ClawSweeper custom-bind fix; shrinkwrap check reported all package shrinkwraps current; branch and local autoreview both reported no accepted/actionable findings.

Observed result after fix: the rebased branch contains only Gateway policy/docs changes on top of current main, with no lockfile or shrinkwrap changes. Policy tests cover the Gateway conformance findings and the custom-bind/runtime-validation alignment cases, including blank custom bind hosts not counting as active non-loopback exposure.

What was not tested: no live Gateway was launched. The proof verifies config-level policy doctor/lint behavior against config and policy inputs.

Related

@github-actions github-actions Bot added the dependencies-changed PR changes dependency-related files label May 15, 2026
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation app: web-ui App: web-ui gateway Gateway runtime cli CLI command changes scripts Repository scripts commands Command implementations agents Agent runtime and tooling extensions: oc-path size: XL maintainer Maintainer-authored PR labels May 15, 2026
@clawsweeper

clawsweeper Bot commented May 15, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge.

Latest ClawSweeper review: 2026-05-22 21:05 UTC / May 22, 2026, 5:05 PM ET.

Workflow note: Future ClawSweeper reviews update this same comment in place.

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.

Summary
The PR adds Policy plugin Gateway exposure conformance checks, docs, and focused tests for Gateway bind, auth, rate-limit, Control UI, Tailscale, remote, HTTP endpoint, and URL-fetch posture.

Reproducibility: not applicable. as a feature PR; there is no current-main bug to reproduce, and the review path is source/proof inspection of the new Policy behavior.

PR rating
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🐚 platinum hermit
Summary: Patch quality looks reasonable after the prior semantic fixes, but mock-only current-head proof keeps the PR below merge-ready confidence.

Rank-up moves:

  • Add redacted current-head openclaw policy check --json or doctor --lint --json output showing Gateway policy findings and an accepted case.
  • Update the PR body with that proof so ClawSweeper can re-review automatically; if it does not, ask a maintainer to comment @clawsweeper re-review.
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.

Real behavior proof
Needs real behavior proof before merge: Needs real behavior proof before merge: the current PR body lists tests and checks, but no current-head redacted CLI output showing the changed Gateway policy behavior; redact private IPs, hostnames, tokens, phone numbers, and non-public endpoints before posting proof. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • New Gateway evidence changes Policy workspace hashes, accepted attestation hashes, and strict doctor/lint results for workspaces that configure Gateway policy rules.
  • The PR defines security posture semantics for Gateway exposure; if maintainers disagree with any interpretation, strict Policy adopters could get misleading pass/fail results.
  • Current-head proof is test/check/autoreview output only and does not show redacted real CLI output for the new policy findings.

Maintainer options:

  1. Require Current-Head CLI Proof (recommended)
    Ask for redacted openclaw policy check --json or doctor --lint --json output from head 5b1b48d showing the new Gateway policy findings and an accepted case before merge.
  2. Accept Attestation Churn Explicitly
    After proof, maintainers can land the new Gateway evidence knowing strict Policy adopters must review and refresh accepted attestation hashes.
  3. Pause For Policy Semantics
    If Gateway exposure conformance semantics are not settled, pause this PR rather than merging a security-policy surface with disputed meanings.

Next step before merge
Manual review is needed because this is a protected maintainer-labeled security-policy PR with compatibility-sensitive attestation semantics and missing current-head real CLI proof, not a narrow automation repair.

Security
Cleared: No concrete supply-chain or runtime security regression was found; the remaining security concern is maintainer approval of the new policy semantics.

Review details

Best possible solution:

Land this only after maintainer approval of the Gateway exposure semantics, current-head redacted CLI proof, and explicit acceptance of the Policy attestation/hash churn for Gateway policy adopters.

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

Not applicable as a feature PR; there is no current-main bug to reproduce, and the review path is source/proof inspection of the new Policy behavior.

Is this the best way to solve the issue?

Yes, conditionally: keeping this as read-only config conformance in the bundled Policy plugin matches the existing Policy architecture, but merge should wait for maintainer acceptance of the semantics and current-head real CLI proof.

Label justifications:

  • P2: This is a normal-priority Policy feature with limited runtime blast radius but meaningful security-posture review needs.
  • merge-risk: 🚨 compatibility: The new Gateway evidence can change strict Policy findings and accepted attestation hashes for workspaces that opt into Gateway policy rules.
  • merge-risk: 🚨 security-boundary: The PR defines Gateway exposure semantics that operators may use as security conformance evidence.
  • rating: 🦪 silver shellfish: Current PR rating is 🦪 silver shellfish because proof is 🦪 silver shellfish, patch quality is 🐚 platinum hermit, and Patch quality looks reasonable after the prior semantic fixes, but mock-only current-head proof keeps the PR below merge-ready confidence.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: Needs real behavior proof before merge: the current PR body lists tests and checks, but no current-head redacted CLI output showing the changed Gateway policy behavior; redact private IPs, hostnames, tokens, phone numbers, and non-public endpoints before posting proof. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Acceptance criteria:

  • redacted openclaw policy check --json or doctor --lint --json on current PR head showing Gateway findings and an accepted case
  • focused Policy doctor/CLI tests if the branch changes again
  • docs sanity for docs/cli/policy.md and docs/plugins/reference/policy.md before landing

What I checked:

  • protected review context: The live PR context marks this PR with the protected maintainer label, plus existing compatibility and security-boundary merge-risk labels, so it should stay open for explicit maintainer handling rather than cleanup close. (5b1b48d38851)
  • PR-head evidence collection: The PR adds optional gatewayExposure to Policy evidence and gates it with includeGatewayExposure, so Gateway evidence is only included when evaluation asks for it. (extensions/policy/src/policy-state.ts:179, 5b1b48d38851)
  • PR-head Gateway posture scan: The new scanner records bind, auth, rate-limit, Control UI, Tailscale, remote-mode, and HTTP endpoint/URL-fetch evidence from existing Gateway config without launching or mutating the Gateway. (extensions/policy/src/policy-state.ts:340, 5b1b48d38851)
  • PR-head policy evaluation gating: Policy evaluation sets includeGatewayExposure from policyHasGatewayRules(policy) and then adds Gateway findings into the existing Policy finding set. (extensions/policy/src/doctor/register.ts:560, 5b1b48d38851)
  • PR-head finding implementation: The PR implements concrete Gateway findings for non-loopback bind, disabled auth, missing explicit rate-limit posture, insecure Control UI toggles, Tailscale Funnel, remote mode, denied HTTP endpoints, and unrestricted URL-fetch inputs. (extensions/policy/src/doctor/register.ts:1385, 5b1b48d38851)
  • custom bind contract alignment: Current Gateway startup rejects missing, blank, or non-canonical IPv4 gateway.customBindHost for gateway.bind=custom; the PR-head scanner now only treats canonical non-127 IPv4 custom hosts as active non-loopback exposure. (src/gateway/server-runtime-config.ts:69, bb5010b89a5a)

Likely related people:

  • Gio Della-Libera: Authored the merged Policy conformance stack commits that introduced and extended the same Policy files and architecture this PR builds on. (role: policy stack feature owner; confidence: high; commits: cbf72e5e26ee, a30ac3f8d7cb, 6dbd5bd4460e; files: extensions/policy/src/doctor/register.ts, extensions/policy/src/policy-state.ts, docs/cli/policy.md)
  • Peter Steinberger: Recent current-main history and blame cover the Policy and Gateway files used as the base contracts for this review, and shortlog shows heavy adjacent activity across these surfaces. (role: recent adjacent area contributor; confidence: medium; commits: 5e97045345a6, bb5010b89a5a; files: extensions/policy/src/doctor/register.ts, extensions/policy/src/policy-state.ts, src/gateway/server-runtime-config.ts)
  • openperf: Introduced the container auto-bind behavior that the PR treats as potentially non-loopback default Gateway exposure. (role: introduced related gateway bind behavior; confidence: medium; commits: c857e9373523; files: src/gateway/net.ts)
  • galiniliev: Provided maintainer review comments on the exact Gateway custom-bind and remote-mode semantics that shaped the current PR head. (role: recent reviewer; confidence: medium; files: extensions/policy/src/policy-state.ts, src/gateway/server-runtime-config.ts)

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

@giodl73-repo

Copy link
Copy Markdown
Contributor Author

Restacked this branch onto the updated policy-secrets-auth-provenance head and reran validation:

  • pnpm protocol:check
  • pnpm check:changed

I also updated the PR body with the required Real behavior proof fields.

@socket-security

socket-security Bot commented May 15, 2026

Copy link
Copy Markdown

No dependency changes detected. Learn more about Socket for GitHub.

👍 No dependency changes detected in pull request

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@giodl73-repo giodl73-repo force-pushed the policy-gateway-exposure-conformance branch 2 times, most recently from e91651b to d4fa5c5 Compare May 16, 2026 06:21
@giodl73-repo giodl73-repo force-pushed the policy-gateway-exposure-conformance branch 5 times, most recently from 3232b3d to d67f0c3 Compare May 16, 2026 21:49
@giodl73-repo giodl73-repo force-pushed the policy-gateway-exposure-conformance branch from 6729aaf to bdd19c2 Compare May 21, 2026 20:17
@giodl73-repo giodl73-repo force-pushed the policy-gateway-exposure-conformance branch from bdd19c2 to 04e8ff0 Compare May 21, 2026 21:05
@clawsweeper clawsweeper Bot added the proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. label May 21, 2026

@galiniliev galiniliev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the policy evidence paths against current gateway runtime contracts. The focused policy tests pass locally, but I found two false-positive evidence cases that should be fixed before this becomes a strict policy gate.

nonLoopback:
bind === undefined
? !tailscaleForcesLoopback
: bind === "custom"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] Don't report invalid custom bind as non-loopback exposure

When gateway.bind is "custom" and gateway.customBindHost is missing or blank, this marks the bind as nonLoopback: true, so strict policy emits policy/gateway-non-loopback-bind. Startup rejects that config before listening (gateway.bind=custom requires gateway.customBindHost), so the policy evidence/attestation says exposed when the actual runtime state is invalid and not listening. Please separate invalid custom-bind config from actual non-loopback exposure, or only set nonLoopback after a concrete non-loopback host exists.

@giodl73-repo giodl73-repo May 21, 2026

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 signed commit b52241b5675d06034e4940aadf4109b2072fffe2.

gateway.bind=custom without a nonblank customBindHost now reports no non-loopback exposure evidence. Host-specific exposure is only emitted from gateway.customBindHost when a concrete host exists, and the custom-host loopback check matches runtime's valid IPv4-only custom bind contract. Added regressions for blank custom host and for localhost / ::1 falling back to LAN exposure.

Comment thread extensions/policy/src/policy-state.ts Outdated
value: "remote",
});
}
if (remote.enabled === true) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Do not treat gateway.remote.enabled as active exposure

gateway.remote.enabled does not enable a runtime path today: gateway callers gate remote behavior on config.gateway?.mode === "remote", and a repo-wide search finds no code reading this field. With this evidence, a config that merely contains gateway.remote.enabled: true fails gateway.remote.allow=false even though no remote mode or URL is active. Please drop this evidence or tie it to an actually-used runtime contract so strict policy does not reject inert config.

@giodl73-repo giodl73-repo May 21, 2026

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 signed commit b52241b5675d06034e4940aadf4109b2072fffe2.

Dropped gateway.remote.enabled as exposure evidence. Remote policy now keys off the runtime contract: gateway.mode === "remote", with gateway.remote.url evidence only when remote mode is active. Added regressions proving inert remote.enabled / remote.url outside remote mode do not fail strict policy.

Proof run on the pushed branch:

  • git diff --check
  • node scripts/run-vitest.mjs extensions/policy/src/doctor/register.test.ts extensions/policy/src/cli.test.ts --run --reporter=dot -> 117 tests passed
  • node node_modules/@typescript/native-preview/bin/tsgo.js -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test-policy-81981-tilde-fix.tsbuildinfo
  • /mnt/c/src/claws-hapi/.agents/skills/autoreview/scripts/autoreview --mode branch --reviewer codex --fallback-reviewer none -> no accepted/actionable findings

@galiniliev galiniliev assigned galiniliev and unassigned steipete May 21, 2026
@giodl73-repo giodl73-repo force-pushed the policy-gateway-exposure-conformance branch from 04e8ff0 to b52241b Compare May 21, 2026 23:09
@giodl73-repo giodl73-repo requested a review from galiniliev May 21, 2026 23:10
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels May 21, 2026

@galiniliev galiniliev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I found one remaining runtime-contract mismatch in the gateway exposure evidence. The earlier blank-custom-bind and inactive-remote cases look fixed on this revision.

Comment thread extensions/policy/src/policy-state.ts Outdated
kind: "bind",
source: "oc://openclaw.config/gateway/customBindHost",
value: customBindHost,
nonLoopback: !isRuntimeLoopbackCustomBindHost(customBindHost),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] Don’t classify invalid custom hosts as active exposure

This now skips a blank customBindHost, but non-IPv4 values such as localhost or ::1 still produce nonLoopback: true evidence and the new tests expect that as a LAN fallback. Gateway startup no longer allows that fallback: resolveGatewayRuntimeConfig rejects gateway.bind=custom unless customBindHost is a valid IPv4 and the resolved bind host matches it (src/gateway/server-runtime-config.ts:69-82). As a result, strict policy can report policy/gateway-non-loopback-bind for a gateway that would fail before listening, which is the same false-positive shape this revision fixed for blank custom hosts. Please gate this evidence on the same valid-IPv4 runtime contract, or surface it as invalid config rather than active non-loopback exposure.

@giodl73-repo giodl73-repo May 21, 2026

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.

Fixed in f559951 after rebasing this stack on the updated #81974 head.

Policy evidence now treats custom bind exposure the same way gateway startup does: a customBindHost only counts as active non-loopback exposure when it is a valid canonical IPv4 and not 127/8. Invalid custom hosts such as localhost, ::1, and non-canonical IPv4 strings no longer produce policy/gateway-non-loopback-bind evidence for a gateway that would fail before listening. A valid LAN IPv4 still reports the exposure.

Proof:

  • git diff --check
  • node scripts/run-vitest.mjs extensions/policy/src/doctor/register.test.ts extensions/policy/src/cli.test.ts --run --reporter=dot
  • node node_modules/@typescript/native-preview/bin/tsgo.js -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test-policy-81981-custom-bind.tsbuildinfo
  • /mnt/c/src/claws-hapi/.agents/skills/autoreview/scripts/autoreview --mode local -> clean, no accepted/actionable findings

@giodl73-repo giodl73-repo force-pushed the policy-gateway-exposure-conformance branch 2 times, most recently from f559951 to 494972e Compare May 22, 2026 05:26
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels May 22, 2026
@giodl73-repo

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot removed the proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. label May 22, 2026
@giodl73-repo

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Improvements or additions to documentation extensions: policy maintainer Maintainer-authored PR merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P2 Normal backlog priority with limited blast radius. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: XL status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants