Goal
Prove whether NIP-98 URL comparison can treat meaningfully different request targets as equivalent, and correct the behavior if confirmed.
Research finding
Source inspection at commit 6b1ea9ff161f1c558659d69f91757272019f32a8 found a permissive fallback in urls_match_for_nip98 that strips trailing / characters from the complete URL string after parsed URL equality fails.
The same verifier is used by the session creation path and protected-request authentication path. The suspected mismatch includes meaningful differences inside query values.
Current evidence is source inspection, not executed validation. Native Rust regression and router-level results remain pending. The earlier synthetic-reproduction claim is not supported by an available execution record and is not counted as proof. No production exploit is claimed.
Source:
|
/// Loose URL compare: normalize trailing slash on path-only roots. |
|
fn urls_match_for_nip98(authorized: &str, expected: &str) -> bool { |
|
fn norm(s: &str) -> String { |
|
let t = s.trim(); |
|
// Strip trailing slash except for scheme://host only handled by Url if available. |
|
if t.len() > 1 && t.ends_with('/') { |
|
t.trim_end_matches('/').to_string() |
|
} else { |
|
t.to_string() |
|
} |
|
} |
|
// Prefer Url equality when both parse. |
|
match ( |
|
NostrUrl::parse(authorized.trim()), |
|
NostrUrl::parse(expected.trim()), |
|
) { |
|
(Ok(a), Ok(e)) => a == e || norm(authorized) == norm(expected), |
|
_ => norm(authorized) == norm(expected), |
|
} |
|
} |
|
|
Plan
- Add a native regression using the real NIP-98 verifier and synthetic signing material.
- Demonstrate the regression against the unmodified implementation.
- Establish the intended trailing-slash compatibility behavior.
- Implement the smallest sufficient correction without broader URL normalization.
- Add positive and negative coverage for relevant path, query, encoding, authority, and port cases.
- Exercise the relevant request-handling path and prove rejection occurs before a protected handler acts.
- Review the complete diff against current
main.
- Run applicable repository checks and private-data scans.
- Rebase on current
main if needed and rerun validation.
- Have the human contributor GPG-sign all commits and push the branch.
- Create a pull request describing the completed work and exact validation results.
Scope
Keep this change limited to NIP-98 URL comparison and directly relevant authentication tests.
Do not include unrelated HTTP/3 work, session redesign, replay protection, dependency upgrades, or opportunistic cleanup.
Acceptance criteria
Working branch
fix/nip98-url-binding
Follow AGENTS.md and docs/COMPACTION-PIN.md. Agents do not stage, commit, push, or alter signing configuration. Use the approved build path; no laptop Cargo or BUILD_LOCAL override. No production changes are part of this work.
Goal
Prove whether NIP-98 URL comparison can treat meaningfully different request targets as equivalent, and correct the behavior if confirmed.
Research finding
Source inspection at commit
6b1ea9ff161f1c558659d69f91757272019f32a8found a permissive fallback inurls_match_for_nip98that strips trailing/characters from the complete URL string after parsed URL equality fails.The same verifier is used by the session creation path and protected-request authentication path. The suspected mismatch includes meaningful differences inside query values.
Current evidence is source inspection, not executed validation. Native Rust regression and router-level results remain pending. The earlier synthetic-reproduction claim is not supported by an available execution record and is not counted as proof. No production exploit is claimed.
Source:
surmount-server/crates/management-ui/src/auth.rs
Lines 451 to 471 in 6b1ea9f
Plan
main.mainif needed and rerun validation.Scope
Keep this change limited to NIP-98 URL comparison and directly relevant authentication tests.
Do not include unrelated HTTP/3 work, session redesign, replay protection, dependency upgrades, or opportunistic cleanup.
Acceptance criteria
Working branch
fix/nip98-url-bindingFollow
AGENTS.mdanddocs/COMPACTION-PIN.md. Agents do not stage, commit, push, or alter signing configuration. Use the approved build path; no laptop Cargo orBUILD_LOCALoverride. No production changes are part of this work.