Skip to content

[Host] Refuse dot segments in registry request paths - #365

Merged
LarsLaskowski merged 26 commits into
mainfrom
claude/nifty-edison-672xkz
Oct 28, 2026
Merged

LarsLaskowski merged 26 commits into
mainfrom
claude/nifty-edison-672xkz

Conversation

@LarsLaskowski

@LarsLaskowski LarsLaskowski commented Oct 28, 2026 •

Copy link
Copy Markdown
Owner

Pull Request

📖 Description

The OCI, Docker Hub and Docker Scout request builders escaped each path segment with Uri.EscapeDataString, which leaves . alone, and System.Uri then collapses . and .. segments (a registered reference such as corp/../../../v2/_catalog addressed /v2/_catalog). Measured on .NET 10, %2E is collapsed as well, so encoding cannot keep the dots; the builders now refuse a repository, tag or digest with a segment that is exactly . or .. and answer as not found, without sending a request or a token request and without logging. This also covers digests a manifest names, and the Docker Scout path, which was built without any escaping and sent with a Bearer token (a tag with ? or # could add a query). It is a bug fix and changes no behavior for valid references.

🎫 Issues

Closes #360

Follow-up issues: #363 (validate DockerHub:UserName at startup), #364 (check the registry host of a registered reference). Decision record 0014 is extended in place.

💬 Reviewer Notes

Security area: Registry and Docker Hub calls. Focus on RegistryReferenceValidator.HasDotSegment and on the call sites of the Uri? builders in OciRegistryClient, DockerHubClient and DockerScoutVulnerabilityProvider (a refusal must happen before any login or token request). The return at DockerHubClient.cs:628 is a defensive guard no input reaches and stays uncovered on purpose.

📑 Test Plan

22 new test methods (47 cases) plus later additions cover each URI builder, digests read from manifests, exact escaped request URIs for the Scout path, and pins that names containing dots (my.app, ..., %2E%2E) are still requested unchanged. Full suite: 941 + 21 tests pass; coverage 98.7 % on new or changed lines, 88.1 % overall; analyzer gate reports no diagnostic.

✅ Checklist

  • I have added or updated Unit Tests for the change.
  • I have tested my changes.
  • I have run Format and Build from .squad/stack.md, and the Analyzer gate reports no diagnostic in a changed file.
  • The Coverage gate in .squad/stack.md passes (line coverage on new or changed production code and overall).
  • I have updated the project documentation (README.md, ARCHITECTURE.md) to reflect my changes.
  • I have read the CONTRIBUTING documentation and followed the project's code style guidelines.
  • New dependencies, if any, were added the way Dependencies in .squad/stack.md prescribes.
  • The C# rules in csharp.instructions.md are followed.

⏭ Next Steps

claude added 25 commits October 28, 2026 16:19
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
@LarsLaskowski
LarsLaskowski marked this pull request as ready for review October 28, 2026 17:50
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018g33ASaUG3htJVXZexd5We
@LarsLaskowski
LarsLaskowski merged commit 0e12042 into main Oct 28, 2026
4 checks passed
@LarsLaskowski
LarsLaskowski deleted the claude/nifty-edison-672xkz branch October 28, 2026 17:52
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Registry request paths pass . and .. repository segments

2 participants