Skip to content

fix: nil pointer dereference DoS via invalid DPoP htu URL#4112

Open
reinkrul wants to merge 5 commits intomasterfrom
fix/dpop-url-parse-nil-deref
Open

fix: nil pointer dereference DoS via invalid DPoP htu URL#4112
reinkrul wants to merge 5 commits intomasterfrom
fix/dpop-url-parse-nil-deref

Conversation

@reinkrul
Copy link
Member

@reinkrul reinkrul commented Mar 25, 2026

Summary

  • crypto/dpop/dpop.gourl.Parse returns (nil, error) for inputs with invalid percent-encoded sequences (e.g. %zz). strip() ignored the error and immediately wrote to the nil pointer, causing a server panic. Fixed by validating the htu claim in Parse() (reject early) and changing strip() to propagate the error through Match().

Attack vector (before fix)

An attacker with access to the internal API crafts a DPoP JWT with htu: "%zz", signs it with their own key, and POSTs it to POST /internal/auth/v2/dpop/validate. dpop.Parse() accepted the token (the only htu guard was != ""), and the subsequent call to Match()strip()url.Parse("%zz")nilpanic. The connection was reset; the server survived due to net/http's per-connection recover, but the endpoint could be degraded by repeated calls.

🤖 Generated with Claude Code

@qltysh
Copy link

qltysh bot commented Mar 25, 2026

2 new issues

Tool Category Rule Count
qlty Structure Function with many returns (count = 18): Parse 2

…URLs

url.Parse returns (nil, error) for strings with invalid percent-encoded
sequences (e.g. "%zz"). strip() ignored the error and dereferenced the
nil pointer, causing a server panic.

Two-layer fix in crypto/dpop/dpop.go:
- Parse() now validates the htu claim is a parseable URL, so tokens with
  a malformed htu are rejected early with a clear error message.
- strip() signature changed to (string, error) so any remaining parse
  failure is propagated through Match() rather than causing a nil deref.

Adds a unit test (TestParseDPoP/invalid_htu_claim_URL) that covers the
regression: a DPoP token with htu="%zz" is rejected at Parse() time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@reinkrul reinkrul force-pushed the fix/dpop-url-parse-nil-deref branch from 65c2686 to 64ea568 Compare March 25, 2026 10:46
@qltysh
Copy link

qltysh bot commented Mar 25, 2026

Qlty

Coverage Impact

⬇️ Merging this pull request will decrease total coverage on master by 0.08%.

Modified Files with Diff Coverage (1)

RatingFile% DiffUncovered Line #s
Coverage rating: B Coverage rating: B
crypto/dpop/dpop.go78.1%163, 234-235...
Total78.1%
🤖 Increase coverage with AI coding...

In the `fix/dpop-url-parse-nil-deref` branch, add test coverage for this new code:

- `crypto/dpop/dpop.go` -- Lines 163, 234-235, 238-239, and 250-251

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens DPoP parsing/matching against malformed htu values that previously could trigger a nil-pointer dereference panic via url.Parse, preventing a DoS on the validation endpoint.

Changes:

  • Add htu URL validation during dpop.Parse() to reject invalid percent-encoding early.
  • Change strip() to return an error and propagate it through DPoP.Match() instead of ignoring parse failures.
  • Add a regression test covering invalid htu URL input.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
crypto/dpop/dpop.go Validates htu URL in Parse(), makes strip() return (string, error), and handles parse errors in Match().
crypto/dpop/dpop_test.go Adds a regression test for invalid htu percent-encoding (%zz).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

reinkrul and others added 3 commits March 25, 2026 13:23
A non-string htu or htm claim (e.g. a JSON number or object) would pass
the empty-string check but then panic on the v.(string) type assertion,
reintroducing a nil/panic vector. Validate the type first so any
non-string value is rejected with a clear error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A non-string htu or htm claim (e.g. a JSON number or object) would pass
the empty-string check but then panic on the v.(string) type assertion,
reintroducing a nil/panic vector. Validate the type first so any
non-string value is rejected with a clear error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

Copilot AI commented Mar 25, 2026

@reinkrul I've opened a new pull request, #4117, to work on those changes. Once the pull request is ready, I'll request review from you.

… validation (#4117)

* Initial plan

* refactor: rename shadowing s variables to htu/htm in Parse()

Co-authored-by: reinkrul <1481228+reinkrul@users.noreply.github.com>
Agent-Logs-Url: https://github.com/nuts-foundation/nuts-node/sessions/a3558c07-9536-44cd-b10a-74d497ac71f4

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: reinkrul <1481228+reinkrul@users.noreply.github.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 3 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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.

3 participants