Harden hostname normalization for repeated trailing dots [AI]#87305
Conversation
|
Codex review: needs maintainer review before merge. Reviewed May 27, 2026, 10:24 AM ET / 14:24 UTC. Summary PR surface: Source 0, Tests +41. Total +41 across 5 files. Reproducibility: yes. Current main keeps repeated trailing dots in URL hostnames and normalizeHostname removes only one terminal dot, so reserved hostname checks can miss repeated-dot variants; the PR body adds terminal proof that the patched guard blocks them before fetch or lookup. Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge Security Review detailsBest possible solution: Land the centralized normalizer hardening after maintainer review confirms the stricter repeated-dot canonicalization is the desired SSRF and SDK behavior. Do we have a high-confidence way to reproduce the issue? Yes. Current main keeps repeated trailing dots in URL hostnames and normalizeHostname removes only one terminal dot, so reserved hostname checks can miss repeated-dot variants; the PR body adds terminal proof that the patched guard blocks them before fetch or lookup. Is this the best way to solve the issue? Yes. Changing the shared normalizer is the narrow maintainable fix because the SSRF classifier, DNS pinning, trusted proxy checks, and test helper already depend on that canonical hostname contract. AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against 5bf1f168d403. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source 0, Tests +41. Total +41 across 5 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
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 PR egg ✨ Hatched: 🌱 uncommon Frosted Patch Peep Hatch commandComment Hatchability rules:
Rarity: 🌱 uncommon. What is this egg doing here?
|
|
Added real behavior proof to the PR body. It runs the production trusted proxy guard path with repeated-dot reserved hostnames and shows each URL is blocked with @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
…aw#87305) * fix: canonicalize trailing hostname dots * test: reuse shared hostname normalization * docs: add changelog entry for PR merge
…026.5.27) (#698) This PR contains the following updates: | Package | Update | Change | |---|---|---| | [ghcr.io/openclaw/openclaw](https://openclaw.ai) ([source](https://github.com/openclaw/openclaw)) | patch | `2026.5.26` → `2026.5.27` | --- ### Release Notes <details> <summary>openclaw/openclaw (ghcr.io/openclaw/openclaw)</summary> ### [`v2026.5.27`](https://github.com/openclaw/openclaw/blob/HEAD/CHANGELOG.md#2026527) [Compare Source](openclaw/openclaw@v2026.5.26...v2026.5.27) ##### Highlights - Safer local/runtime boundaries: OpenClaw now rejects unsafe command wrappers, malformed CLI numeric options, unsafe Node runtime env overrides, no-auth Tailscale exposure, and non-admin device-role pairing approvals before they can affect live runs. ([#​87308](openclaw/openclaw#87308), [#​87305](openclaw/openclaw#87305), [#​87292](openclaw/openclaw#87292), [#​87146](openclaw/openclaw#87146)) - Matrix and auto-reply delivery are steadier: mention previews stay inert, final mention replies deliver normally, shared-DM notices are awaited, MXID parsing ignores filenames, and reasoning-prefixed `NO_REPLY` responses stay suppressed. - Provider and agent reliability improved across OpenAI-compatible embeddings, cached token usage, Anthropic/Codex/Claude runtime state, unsupported tool-schema quarantine, heartbeat templates, and session fallback errors. ([#​85269](openclaw/openclaw#85269), [#​82062](openclaw/openclaw#82062), [#​85416](openclaw/openclaw#85416), [#​86855](openclaw/openclaw#86855)) - Plugin and package release paths got tighter: Pixverse ships as an external video plugin with region selection, package exclusions and shrinkwrap inventory match the published npm shape, and release/package smoke commands fail bounded instead of hanging. - Gateway hot paths do less rediscovery by reusing current plugin metadata fingerprints, stable plugin index fingerprints, read-only session metadata, active working stores, status fast paths, and auth/env snapshots. ([#​86439](openclaw/openclaw#86439)) ##### Changes - Memory: add a core OpenAI-compatible embedding provider for local and hosted OpenAI-style endpoints, with config, doctor, and docs support. ([#​85269](openclaw/openclaw#85269)) Thanks [@​dutifulbob](https://github.com/dutifulbob). - Plugin SDK: mark memory-specific embedding provider registration as deprecated compatibility and surface non-bundled usage in plugin compatibility diagnostics. ([#​85072](openclaw/openclaw#85072)) Thanks [@​mbelinky](https://github.com/mbelinky). - Pixverse: add video generation provider support, API region selection, and external plugin publishing. - Plugins: expose approval action metadata for plugin-driven approval surfaces. ##### Fixes - Security/CLI/runtime: harden hostname normalization for repeated trailing dots, block side-effecting command wrappers, reject unsafe Node runtime env overrides, reject loose numeric CLI and gateway options, require admin approval for node device-role pairing, and reject no-auth Tailscale exposure. ([#​87305](openclaw/openclaw#87305), [#​87292](openclaw/openclaw#87292), [#​87308](openclaw/openclaw#87308), [#​87146](openclaw/openclaw#87146)) Thanks [@​pgondhi987](https://github.com/pgondhi987). - Doctor: validate runtime tool schemas for every configured embedded agent while skipping ACP-only profiles, so bad non-default plugin or MCP tools are reported before assistant turns. - Telegram: route `sendMessage` action replies through durable outbound delivery so completed agent responses remain retryable when the gateway send path times out. ([#​87261](openclaw/openclaw#87261)) Thanks [@​mbelinky](https://github.com/mbelinky). - Matrix/auto-reply: keep draft previews mention-inert, preserve final mention delivery, send mention finals normally, await shared DM notices, ignore filename-embedded MXIDs, and suppress reasoning-prefixed `NO_REPLY` responses. - Agents/providers: add OpenAI-compatible cache retention, forward cached token usage in chat completions, preserve runtime context before active user turns, strip stale Anthropic thinking, load Claude CLI OAuth for Pi auth profiles, avoid false Codex runtime live switches, and quarantine unsupported tool schemas. ([#​82062](openclaw/openclaw#82062), [#​87167](openclaw/openclaw#87167), [#​86855](openclaw/openclaw#86855)) - Gateway/performance: cache plugin metadata fingerprints and stable plugin index fingerprints, borrow read-only session metadata safely, keep the active session working store hot, keep status on a bounded fast path, and preserve model auth profile suffixes. ([#​86439](openclaw/openclaw#86439)) - Package/install/release: align npm package exclusions and inventory, omit unpacked test helpers, skip Homebrew until macOS packages need it, cap tsdown heap in containers, bound install/release smoke waits, and harden post-publish verification. - Codex/Auth: bound ChatGPT OAuth token exchange and refresh requests, and honor cancellation across Codex and Anthropic OAuth login flows. - QA/E2E/CI: bound Telegram, kitchen-sink, Open WebUI, ClawHub, MCP, Discord, realtime, labeler, and GitHub API waits; fail empty explicit test, live-media, gateway CPU, startup benchmark, plugin gauntlet, and beta-smoke runs instead of false-greening. - Agents/Codex: keep spawned agent bootstrap files rooted in the agent workspace while running task commands, transcripts, and compaction from the requested cwd. ([#​87218](openclaw/openclaw#87218)) Thanks [@​mbelinky](https://github.com/mbelinky). </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwMS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL3BhdGNoIl19--> Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/698
…aw#87305) * fix: canonicalize trailing hostname dots * test: reuse shared hostname normalization * docs: add changelog entry for PR merge
…aw#87305) * fix: canonicalize trailing hostname dots * test: reuse shared hostname normalization * docs: add changelog entry for PR merge
Summary
Linked context
Which issue does this close?
No public issue is closed by this PR body.
Which issues, PRs, or discussions are related?
No public related context is linked here.
Was this requested by a maintainer or owner?
No public maintainer request is linked here.
Real behavior proof (required for external PRs)
fetchWithSsrFGuardtrusted proxy path withHTTPS_PROXY=http://127.0.0.1:7890; fetch and DNS lookup were instrumented as dispatch canaries.HTTPS_PROXY=http://127.0.0.1:7890 ./node_modules/.bin/tsx --eval '<script importing fetchWithSsrFGuard and calling repeated-dot reserved URLs in TRUSTED_ENV_PROXY mode>'localhost,metadata.google.internal,.localhost,.local, and.internalhostnames are rejected before DNS lookup or fetch dispatch in trusted proxy mode.Tests and validation
Which commands did you run?
node scripts/run-vitest.mjs src/infra/net/hostname.test.ts src/infra/net/ssrf.test.ts src/infra/net/fetch-guard.ssrf.test.tsnode scripts/run-vitest.mjs src/infra/net/hostname.test.ts src/infra/net/ssrf.test.ts src/infra/net/fetch-guard.ssrf.test.ts extensions/google/image-generation-provider.test.tsgit diff --check origin/main...HEADnode scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.core.json src/infra/net/hostname.ts src/infra/net/hostname.test.ts src/infra/net/ssrf.test.ts src/infra/net/fetch-guard.ssrf.test.ts src/test-helpers/ssrf.tsWhat regression coverage was added or updated?
Canonical hostname normalization now covers repeated trailing dots. SSRF policy tests cover blocked reserved hostnames with repeated trailing dots. Trusted proxy guard tests cover rejection before lookup or fetch dispatch. The plugin-facing SSRF test helper now reuses the shared normalizer.
What failed before this fix, if known?
Repeated terminal dots could leave a hostname outside the canonical exact/suffix blocked forms.
If no test was added, why not?
Tests were added.
Risk checklist
Did user-visible behavior change? (
Yes/No)Yes, malformed or unusual repeated-dot forms of blocked hostnames are now rejected consistently.
Did config, environment, or migration behavior change? (
Yes/No)No.
Did security, auth, secrets, network, or tool execution behavior change? (
Yes/No)Yes, network hostname guard canonicalization is stricter for repeated trailing dots.
What is the highest-risk area?
Network guard hostname canonicalization is shared by SSRF policy and SDK-exposed helpers.
How is that risk mitigated?
The implementation is a narrow canonicalization change with focused normalizer, SSRF policy, trusted proxy guard, helper-parity regression coverage, and terminal guard-boundary proof.
Current review state
What is the next action?
Await ClawSweeper re-review, CI status, and maintainer review.
What is still waiting on author, maintainer, CI, or external proof?
ClawSweeper re-review and maintainer review are pending. CI has an unrelated existing
check-lintfailure in an unchanged file.Which bot or reviewer comments were addressed?
ClawSweeper requested real behavior proof; the PR body now includes terminal guard-boundary proof showing repeated-dot reserved hostnames blocked before fetch or DNS lookup.