OpenZeppelin / OpenZeppelin/guardian
GET /pubkey and GetPubkey silently serve the Falcon identity for an unrecognized scheme
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 10
- Forks
- 20
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 43
Description
GET /pubkey and GetPubkey silently serve the Falcon identity for an unrecognized scheme
Summary
Both acknowledgement-pubkey handlers treat any scheme value that is not
ecdsa as Falcon, including values that are neither. A typo (scheme=ecsda,
scheme=falcon2, scheme=bogus) returns HTTP 200 with the Falcon
acknowledgement commitment, so a caller that meant ECDSA silently verifies
against the wrong identity instead of getting an error.
Confirmed live: scheme=bogus returns the Falcon commitment.
Where
Identical fall-through in both transports:
crates/server/src/api/grpc.rs:240-243crates/server/src/api/http.rs:474-477
let scheme = match req.scheme.as_deref() {
Some(s) if s.eq_ignore_ascii_case("ecdsa") => SignatureScheme::Ecdsa,
_ => SignatureScheme::Falcon,
};
The strict parser already exists and is unused here:
SignatureScheme::from (crates/shared/src/lib.rs:32-38) accepts falcon and
ecdsa case-insensitively and returns
Err("unsupported signature scheme: {value}") otherwise.
Why it matters
GUARDIAN holds one acknowledgement identity per signature scheme, and an
account's guardian storage slot holds the one matching its own scheme. A
caller that asks for the wrong identity and is served a valid-looking answer
gets a commitment mismatch far from the cause. That is exactly the
misdiagnosis pattern that #432 / F13 produced on the client side: the failure
pointed at the endpoint rather than at which identity was queried.
Typed SDK callers are not exposed (the Rust client passes
SignatureScheme::as_str(); the TypeScript client's getPubkey(scheme?: SignatureScheme) is typed). The exposure is hand-rolled HTTP and gRPC
callers: curl, operator scripts, and non-first-party integrations.
Proposed behaviour
schemeabsent: keep serving Falcon. This is the documented default
(optional string schemeinguardian.proto:235-237, and the/pubkeydoc
comment inhttp.rs) and must not change.schemepresent and recognized (falcon/ecdsa, case-insensitive):
unchanged.schemepresent and unrecognized: reject, naming the value and the
accepted set. HTTP 400, gRPCINVALID_ARGUMENT.
Delegating to SignatureScheme::from gives all three, and removes the
duplicated inline match from both transports.
Scope note
This adds a new error path to a public endpoint on both transports, so it is a
wire-contract change and needs the AGENTS.md §4 workflow: proto/HTTP surface,
OpenAPI (docs/openapi-client.json, crates/server/src/openapi.rs), both
clients, the error-code reference in docs/TROUBLESHOOTING.md, and tests on
both handlers (grpc.rs:724-740, http.rs:882-892 already cover the
absent/ecdsa cases and are the place to add the rejected case).
Found while reviewing #432 (endpoint commitment scheme binding); pre-existing
and out of scope for that fix.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with SignatureScheme::from in crates/shared/src/lib.rs, then inspect the duplicated scheme handling in crates/server/src/api/grpc.rs and crates/server/src/api/http.rs. Review the existing handler tests at grpc.rs:724-740 and http.rs:882-892, along with the AGENTS.md §4 workflow and named client, OpenAPI, and troubleshooting files. Done means absent and recognized schemes retain their behavior while an unrecognized value returns HTTP 400 or gRPC INVALID_ARGUMENT with tests covering both transports.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100