Skip to content

refactor(sdk): shared wire-request decode and pure DPNS/DashPay document builders - #4389

Open
PastaPastaPasta wants to merge 4 commits into
refactor/dash-platform-queriesfrom
refactor/document-query-decode-builders
Open

refactor(sdk): shared wire-request decode and pure DPNS/DashPay document builders#4389
PastaPastaPasta wants to merge 4 commits into
refactor/dash-platform-queriesfrom
refactor/document-query-decode-builders

Conversation

@PastaPastaPasta

@PastaPastaPasta PastaPastaPasta commented Aug 13, 2026

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

Third slice of the feat/transport-free-embedder-core series (#4335; after #4344, #4345, and #4388): gives transport-free embedders the remaining pieces they need to construct and verify Platform interactions without reimplementing SDK logic — the drift-prone code Dash Core's Platform GUI (PastaPastaPasta/dash#67, dashpay/dash#7512) currently hand-builds in C++.

Stacked on #4388 (base branch refactor/dash-platform-queries); will be retargeted to v4.2-dev when that merges. Only the last four commits are new.

What was done?

  • Wire-request decode: DocumentQuery::try_from_request decodes a wire-format GetDocumentsRequest back into a rich DocumentQuery — the inverse of request encoding — by lifting drive-abci's server-side proto conversions into shared client code, so the bytes the server decodes and the client verifies go through the same code. drive-abci now consumes the shared conversions (deduplicated, −382 lines in its conversions.rs). Round-trip coverage in tests/document_query_wire_roundtrip.rs.
  • Request-driven proof verification: documents::verify_documents_response delegating to drive-proof-verifier's FromProof, keyed on the exact request bytes sent. It binds the proof to the whole request, not just the part that survives lowering: GroveDB/Tenderdash proofs authenticate the state and the resolved DriveDocumentQuery, and the DocumentQueryDriveDocumentQuery lowering drops group_by, having, offset and prove — so each of those is rejected up front, mirroring rs-drive-abci's validate_and_route and reject_offset_off_the_ranked_path. Without that, an untrusted transport could pair a request the real server would have refused (SELECT DOCUMENTS … GROUP BY age) with a genuine proof for the narrower query it lowers to. The limit conversion is likewise checked (u16::try_from) rather than an as cast, which silently turned a request for 65537 documents into a 1-document query.
  • Pure document builders: build_dpns_preorder_and_domain_documents (salted-domain-hash preorder/domain pair) and dashpay::build_contact_request_document, extracted from rs-sdk's networked flows. Crypto material is supplied by the caller — ECDH/key custody stays out of this crate.
  • Consensus-aligned DPNS validation: split is_consensus_valid_label (matches the DPNS contract regex; gates the builders) from is_valid_username (stricter client-side policy, e.g. consecutive-hyphen rejection) so builders cannot reject labels the contract accepts.
  • rs-sdk re-exports everything at its old paths; no consumer changes imports.

How Has This Been Tested?

Breaking Changes

None beyond those already declared by the base PR #4388. Moved items remain importable at their previous dash_sdk paths; drive-abci's request decoding behavior is unchanged (same conversions, now shared).

One behavior change worth calling out: TryFrom<&DocumentQuery> for DriveDocumentQuery now returns an error for a limit above u16::MAX instead of wrapping it. The server rejects such limits outright (QuerySyntaxError::InvalidLimit), so the previous as cast could only ever produce a query the caller did not ask for. No existing test depended on the truncation.

@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9e56606a-cecc-4a76-99bf-b5f9f4c73632

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@thepastaclaw

thepastaclaw commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

⛔ Blockers found — Opus deferred (commit 5435934)
Canonical validated blockers: 2

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Preliminary review — Codex only

The shared decoders and extracted builders largely preserve the existing behavior, but the new request-driven document verifier does not bind verification to every semantically relevant request field. A malicious transport can therefore substitute a valid proof for a different query, so this trust-boundary issue must be fixed before merging.
Source: reviewer backend model gpt-5.6-sol; final verifier backend model gpt-5.6-sol. Orchestration-only: openclaw-agent/cliproxy/gpt-5.6-sol (not reviewer evidence).

Validated blockers were found in the Codex precheck. Opus is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 1 blocking

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/dash-platform-queries/src/documents/document_query.rs`:
- [BLOCKING] packages/dash-platform-queries/src/documents/document_query.rs:665-678: Reject request fields that are discarded before proof verification
  Validating only the `select` projection does not ensure that the proof corresponds to the wire request. The subsequent `TryFrom<&DocumentQuery> for DriveDocumentQuery` conversion discards `group_by` and `having`, even though the server rejects both for `SELECT DOCUMENTS`; consequently, an untrusted transport can pair a request such as `SELECT DOCUMENTS GROUP BY age` with a valid proof for the corresponding plain document query and this function will accept it. The conversion also narrows `request.limit` with `as u16` at lines 1127-1129, so a wire limit of 65537 becomes 1 even though the server rejects limits above `u16::MAX`. Plain-document `offset` and a false `prove` flag are additional request shapes that cannot produce this proved response from the real server but are not rejected here. GroveDB and Tenderdash proofs authenticate the state and resolved Drive query, not the discarded request envelope. Before delegating, reject every field incompatible with a proved plain-document request (`group_by`, `having`, `offset`, and `prove == false`) and use a checked `u16::try_from` conversion for the limit so no request information is silently changed.

Comment on lines +665 to +678
// This entry point verifies plain document fetches only. An aggregate
// projection (COUNT/SUM/AVG) is proved with a different proof shape;
// handing it to the Documents verifier would surface as an opaque
// low-level proof error, so reject it up front instead.
if query.select != drive::query::SelectProjection::documents() {
return Err(drive_proof_verifier::Error::RequestError {
error: format!(
"verify_documents_response only verifies plain document fetches; the request \
carries a {:?} projection — use the aggregate proof helpers instead",
query.select.function
),
});
}
<Documents as FromProof<DocumentQuery>>::maybe_from_proof_with_metadata(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔴 Blocking: Reject request fields that are discarded before proof verification

Validating only the select projection does not ensure that the proof corresponds to the wire request. The subsequent TryFrom<&DocumentQuery> for DriveDocumentQuery conversion discards group_by and having, even though the server rejects both for SELECT DOCUMENTS; consequently, an untrusted transport can pair a request such as SELECT DOCUMENTS GROUP BY age with a valid proof for the corresponding plain document query and this function will accept it. The conversion also narrows request.limit with as u16 at lines 1127-1129, so a wire limit of 65537 becomes 1 even though the server rejects limits above u16::MAX. Plain-document offset and a false prove flag are additional request shapes that cannot produce this proved response from the real server but are not rejected here. GroveDB and Tenderdash proofs authenticate the state and resolved Drive query, not the discarded request envelope. Before delegating, reject every field incompatible with a proved plain-document request (group_by, having, offset, and prove == false) and use a checked u16::try_from conversion for the limit so no request information is silently changed.

source: ['codex']

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Verified against rs-drive-abci and fixed — this was a real hole.

Server rules confirmed in packages/rs-drive-abci/src/query/document_query/v1/mod.rs:

  • validate_and_route, SelectFunction::Documents arm: non-empty group_byInvalidArgument.
  • validate_and_route, ahead of the per-function gates: non-empty having with a non-aggregate SELECT → not_yet_implemented("HAVING clause").
  • reject_offset_off_the_ranked_path: offset.is_some() on any non-Ranked decision → not_yet_implemented("OFFSET pagination …"). A documents fetch never routes to Ranked.
  • query_documents_typed (v0/mod.rs, shared by both wire versions): limit > u16::MAXQuerySyntaxError::InvalidLimit.

So all four are shapes an honest server refuses, and all four are dropped by the DocumentQueryDriveDocumentQuery lowering. prove == false isn't a server rejection but has the same effect: the server answers without a proof, so a proved response cannot belong to that request.

Changes:

  • New reject_request_the_server_would_not_have_proved(&query, prove) gate in verify_documents_response, run before delegating to FromProof. It rejects prove == false, non-documents projections (the pre-existing check, moved in), non-empty having, non-empty group_by, and any offset. prove is read off the wire request before decode, since DocumentQuery has no such field.
  • TryFrom<&DocumentQuery> for DriveDocumentQuery now uses u16::try_from for the limit. You were right that this one is objectively wrong independent of the security argument — 65537 wrapped to 1. It now matches the offset conversion immediately below it, which already refused rather than truncated.
  • Five tests in tests/document_query_wire_roundtrip.rs (verify_binds_the_whole_request::*) plus limit_above_u16_max_is_rejected_not_truncated. The tests pass a ContextProvider that panics on every method, so they also pin that the rejection fires before any proof machinery runs.

try_from_request itself is unchanged — it still decodes these fields faithfully, which is what makes it a true inverse of encoding. Its "scope caveat" doc now points at the entry point that closes the gap.

No existing test expectations changed.


🤖 Posted autonomously by Claude on behalf of pasta.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Resolved in this update — Reject request fields that are discarded before proof verification no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

PastaPastaPasta added a commit to PastaPastaPasta/dash that referenced this pull request Aug 13, 2026
…-builders base

Move all seven dashpay/platform git dependencies from the old feat/transport-free-embedder-core pin (e8e1961fe54f) to rev 2a6dbe39065104981b7f9bb4fbee598aab869fe4, the head of refactor/document-query-decode-builders (PR dashpay/platform#4389) whose content is the rebased equivalent on the current v4.2-dev base. No FFI-visible API drift: the crate builds unchanged and all 31 rust/platform tests pass against the new revision.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@PastaPastaPasta
PastaPastaPasta force-pushed the refactor/dash-platform-queries branch from fb66886 to 097eadb Compare August 13, 2026 16:57
@PastaPastaPasta
PastaPastaPasta force-pushed the refactor/document-query-decode-builders branch from 2a6dbe3 to 4f1c1bd Compare August 13, 2026 16:57
@PastaPastaPasta
PastaPastaPasta force-pushed the refactor/dash-platform-queries branch from 097eadb to 84841a8 Compare August 13, 2026 17:34
@PastaPastaPasta
PastaPastaPasta force-pushed the refactor/document-query-decode-builders branch from 4f1c1bd to be3375f Compare August 13, 2026 17:36
@PastaPastaPasta
PastaPastaPasta force-pushed the refactor/dash-platform-queries branch from 84841a8 to 9970e9f Compare August 13, 2026 19:17
@PastaPastaPasta
PastaPastaPasta force-pushed the refactor/document-query-decode-builders branch from be3375f to 5596a4c Compare August 13, 2026 19:17

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Preliminary review — Codex only

The shared proto conversions and extracted document builders generally preserve existing behavior and add useful deterministic coverage. However, the request-driven verifier still reduces the wire request to a narrower Drive query without validating every field that the server uses for routing, allowing a fabricated response to verify against a request the server would reject.
Source: reviewer backend model gpt-5.6-sol; final verifier backend model gpt-5.6-sol. Orchestration-only: openclaw-agent/cliproxy/gpt-5.6-sol (not reviewer evidence).

Validated blockers were found in the Codex precheck. Opus is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 1 blocking

1 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/dash-platform-queries/src/documents/document_query.rs`:
- [BLOCKING] packages/dash-platform-queries/src/documents/document_query.rs:681-694: Reject request fields that are discarded before proof verification
  (existing thread: https://github.com/dashpay/platform/pull/4389#discussion_r3771773859)
  Checking only that `select` is the documents projection does not bind verification to the complete wire request. The subsequent `TryFrom<&DocumentQuery> for DriveDocumentQuery` conversion discards `group_by` and `having`, although the server rejects both when used with `SELECT DOCUMENTS`. It also narrows a nonzero `u32` limit with `as u16`, so a request for 65537 documents is verified as a limit-1 query even though the server rejects limits above `u16::MAX`. A plain-document `offset` is lowered into a Drive query despite being rejected by the server's routing layer, and `prove == false` is ignored even though an honest server cannot return this proved response for such a request. Consequently, an untrusted transport can pair one of these server-invalid requests with a valid proof for the reduced Drive query and this function accepts it. Before delegating, reject nonempty `group_by` or `having`, any plain-document `offset`, and `prove == false`, and convert the limit with `u16::try_from` so no request information is silently changed.

PastaPastaPasta and others added 4 commits August 13, 2026 16:22
…d client code

The proto-to-domain decoding for document queries existed only server-side
(rs-drive-abci's v1 conversions), so a client verifying a documents proof had
to reconstruct the query shape by hand and could silently drift from what the
server actually proves. Move the decode logic into
dash-platform-queries::documents::proto_conversions with a neutral error
type; drive-abci's conversions module becomes a thin mapping onto its
QueryError surface with identical error message strings.

On top of the shared decoder, DocumentQuery::try_from_request(request,
contract) reconstructs the rich query from the wire request (both request
versions), and verify_documents_response(...) /
verify_documents_response_with_provider_contract(...) give embedders a
request-driven verification entry point that delegates to the existing
FromProof machinery, resolving the contract explicitly or via
ContextProvider::get_data_contract.

Round-trip tests cover encode-decode equality for representative queries in
both wire versions plus malformed-clause rejection; drive-abci's
document_query unit tests pass unchanged (76 cases).
Move the document *content* assembly of rs-sdk's networked DPNS and DashPay flows into transport-free functions in dash-platform-queries, so offline/embedder consumers and rs-sdk share one implementation:

- build_dpns_preorder_and_domain_documents assembles the preorder and domain documents exactly as register_dpns_name did: both ids from the same entropy via generate_document_id_v0, saltedDomainHash = sha256d(salt || normalized_label + ".dash"), and the full domain property map (parentDomainName/normalizedParentDomainName, label, normalizedLabel, preorderSalt, records.identity, subdomainRules.allowSubdomains=false). It additionally rejects labels failing is_valid_username up front - previously only enforced by rs-sdk-ffi and platform consensus - so register_dpns_name now fails locally on an invalid label instead of after a network round-trip.

- build_contact_request_document assembles the DIP-15 contactRequest id and property map from already-derived crypto material (encrypted xpub/label bytes, key indices, entropy). ECDH, encryption, the 69-byte compact-xpub check, key purpose checks, and recipient fetching stay in rs-sdk; the ciphertext size validations (96-byte xpub, 48-80-byte label, 38-102-byte autoAcceptProof) moved into the builder, with validate_auto_accept_proof also called early in create_contact_request to keep the pre-fetch fail-fast.

- ensure_entropy_matches_document_id and prepare_document_for_transition moved from put_document.rs into dash_platform_queries::transition::put_document; rs-sdk re-exports and keeps calling them.

Entropy/salt generation and all networking remain in rs-sdk. Builder validation errors surface through the new dash_platform_queries::Error::InvalidInput variant, which rs-sdk maps back to Error::Generic with the exact pre-move messages. New unit tests in dash-platform-queries pin a DPNS known vector (document ids and property maps for fixed label/entropy/salt), mirror the entropy-derives-id relation for contact requests, and cover the negative validation paths.
…er seams

Review follow-ups on the transport-free series:

- The DPNS document builder validated labels with is_valid_username, whose
  consecutive-hyphen rejection is stricter than the DPNS contract's schema
  pattern - consensus accepts names like ab--cd. Split the check: new
  is_consensus_valid_label matches the contract pattern exactly and gates
  the builder (so dash-sdk's register_dpns_name no longer refuses
  consensus-valid labels), while is_valid_username keeps the stricter
  policy for its existing FFI/wasm gates and now documents the difference.
- verify_documents_response now binds the proof to the whole wire request,
  not just its SELECT projection. GroveDB and Tenderdash proofs authenticate
  the state and the resolved DriveDocumentQuery, and the DocumentQuery ->
  DriveDocumentQuery lowering drops group_by, having, offset and prove - so
  an untrusted transport could otherwise pair a request the real server
  would have refused (SELECT DOCUMENTS ... GROUP BY age) with a genuine
  proof for the narrower query it lowers to, and verification would accept
  it. Every dropped field is now rejected up front, mirroring rs-drive-abci's
  validate_and_route (non-empty HAVING for a non-aggregate SELECT, GROUP BY
  under SELECT DOCUMENTS) and reject_offset_off_the_ranked_path (OFFSET off
  the ranked surface); prove=false is rejected because an honest server
  answers such a request without a proof at all. The pre-existing aggregate-
  projection rejection (COUNT/SUM/AVG, which use a different proof shape)
  moves into the same gate. Five tests cover the rejections with a
  ContextProvider that panics if reached, pinning that they fire before any
  proof machinery runs.
- TryFrom<&DocumentQuery> for DriveDocumentQuery converts the limit with a
  checked u16::try_from instead of an `as` cast. Drive's limit is a u16 and
  the server refuses anything larger with InvalidLimit, so the cast turned a
  request for 65537 documents into a 1-document query - and a proof for that
  query then verified. This matches the offset conversion right below it,
  which already refused rather than truncated.
- try_from_request documents that it mirrors the server's wire-shape decode,
  not validate_and_route business rules, and points at the entry point that
  closes the gap.
- The CI transport-leak guard also asserts wasm-sdk's wasm32 tree stays
  free of the native transport stack.
- The proof-vector corpus gains a README with an explicit coverage matrix:
  the four documents-family cases pin query shape and clean decode failure
  but stop before the BLS check (placeholder payloads in the fixture
  state); identity, contested, and quorum-sig families run the full
  pipeline. This corrects the corpus commit's broader claim.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@PastaPastaPasta
PastaPastaPasta force-pushed the refactor/dash-platform-queries branch from 9970e9f to 7087bd2 Compare August 13, 2026 21:30
@PastaPastaPasta
PastaPastaPasta force-pushed the refactor/document-query-decode-builders branch from 5596a4c to 5435934 Compare August 13, 2026 21:30

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Preliminary review — Codex only

The prior request-envelope binding issue is fixed: discarded fields are now rejected before proof verification, and limit narrowing is checked. Two server-parity gaps remain in the new request-driven verifier: it accepts wire versions disabled by the supplied PlatformVersion and explicit document limits above the server's canonical cap, allowing proofs to authenticate request/response pairings that an honest server could not produce.
Source: reviewer backend model gpt-5.6-sol; final verifier backend model gpt-5.6-sol.
Orchestration-only: openclaw-agent/cliproxy/gpt-5.6-sol (not reviewer evidence).

Validated blockers were found in the Codex precheck. Opus is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 2 blocking

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `packages/dash-platform-queries/src/documents/document_query.rs`:
- [BLOCKING] packages/dash-platform-queries/src/documents/document_query.rs:761-767: Reject document wire versions unavailable at the target platform version
  The verifier dispatches on the request oneof without checking whether that wire version is enabled by `platform_version.drive_abci.query.document_query`. The server performs this check in `rs-drive-abci/src/query/document_query/mod.rs` before decoding or executing the request. For example, PlatformVersions 1–11 have bounds `min_version = 0, max_version = 0`, so their servers reject every V1 request with `UnsupportedQueryVersion`; this verifier instead decodes the V1 request and can verify a genuine V0 proof for the equivalent lowered `DriveDocumentQuery`. An untrusted transport can therefore attach a valid proof to a request that an honest server at the supplied PlatformVersion could not have answered. Derive the request feature version (`V0 = 0`, `V1 = 1`) and reject it unless the supplied version bounds accept it before decoding or delegating to `FromProof`.
- [BLOCKING] packages/dash-platform-queries/src/documents/document_query.rs:1234-1245: Enforce the server's document limit cap during verification
  The checked `u16` conversion prevents wrapping, but it still accepts explicit limits from 101 through 65535. The server passes the converted value to `DriveDocumentQuery::from_typed_clauses`, which rejects any value above `DriveConfig::default().default_query_limit` (`DEFAULT_QUERY_LIMIT`, currently 100). The verifier bypasses that constructor and creates a raw `DriveDocumentQuery` with values such as `limit = Some(101)`. If the matching range contains fewer documents than either limit, a genuine proof for a server-valid query can also satisfy the larger path query, so verification accepts a fabricated request/response pairing that an honest server would reject. Validate explicit plain-document limits against the same canonical limit used by proof verification, rather than only checking whether they fit in `u16`.

Comment on lines +761 to +767
let prove = match &request.version {
Some(V0(v0)) => v0.prove,
Some(V1(v1)) => v1.prove,
// Missing version is reported by the decode below.
None => true,
};
let query = DocumentQuery::try_from_request(request, contract).map_err(|e| {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔴 Blocking: Reject document wire versions unavailable at the target platform version

The verifier dispatches on the request oneof without checking whether that wire version is enabled by platform_version.drive_abci.query.document_query. The server performs this check in rs-drive-abci/src/query/document_query/mod.rs before decoding or executing the request. For example, PlatformVersions 1–11 have bounds min_version = 0, max_version = 0, so their servers reject every V1 request with UnsupportedQueryVersion; this verifier instead decodes the V1 request and can verify a genuine V0 proof for the equivalent lowered DriveDocumentQuery. An untrusted transport can therefore attach a valid proof to a request that an honest server at the supplied PlatformVersion could not have answered. Derive the request feature version (V0 = 0, V1 = 1) and reject it unless the supplied version bounds accept it before decoding or delegating to FromProof.

source: ['codex']

Comment on lines 1234 to 1245
let limit = if request.limit != 0 {
Some(request.limit as u16)
Some(u16::try_from(request.limit).map_err(|_| {
Error::Config(format!(
"limit {} does not fit a documents query's u16 limit (max {}); \
the server rejects such limits with InvalidLimit",
request.limit,
u16::MAX
))
})?)
} else {
None
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔴 Blocking: Enforce the server's document limit cap during verification

The checked u16 conversion prevents wrapping, but it still accepts explicit limits from 101 through 65535. The server passes the converted value to DriveDocumentQuery::from_typed_clauses, which rejects any value above DriveConfig::default().default_query_limit (DEFAULT_QUERY_LIMIT, currently 100). The verifier bypasses that constructor and creates a raw DriveDocumentQuery with values such as limit = Some(101). If the matching range contains fewer documents than either limit, a genuine proof for a server-valid query can also satisfy the larger path query, so verification accepts a fabricated request/response pairing that an honest server would reject. Validate explicit plain-document limits against the same canonical limit used by proof verification, rather than only checking whether they fit in u16.

source: ['codex']

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.

2 participants