Replies: 1 comment
-
|
I'm not completely convinced that we should frame this as native grpc support specifically. gRPC is only one RPC framework (by Google), I mean if we build the architecture around gRPC as a special-case protocol, we may end up solving only that one case while leaving the broader class of RPC-style targets untouched. I see the problem not as "nuclei cannot speak gRPC", but "nuclei has no good model for testing RPC-style services" because gRPC is one case of that. XML-RPC, JSON-RPC, Apache Thrift, Java RMI, .NET Remoting, etc., are differ in transport/schema/encoding, but from my PoV they are all variations of the same basic shape. So I would rather see the design start from that model and ask whether we should leave room for those other protocols to fit into the same conceptual model, rather than introducing a gRPC-specific shape that later becomes hard to generalize, and then someday discover that every other RPC protocol needs its own incompatible one-off design. The same concern applies to serialization. Tbh the |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
RFC: Native gRPC Protocol Support
Status
Abstract
Nuclei ships native protocol support for HTTP, DNS, network/TCP, SSL, WebSocket,
WHOIS, headless, file, code, and JavaScript, but it has no native gRPC
protocol. Authors who want to test gRPC endpoints today must shell out to
external tooling (
grpcurl/evans) through thecodeprotocol, which is gated,requires template signing, and produces no first-class request/response model for
matchers and extractors.
This RFC proposes a native
grpcprotocol that lets template authors describe aunary gRPC call declaratively, supplies the request message as JSON (marshaled to
Protocol Buffers via server reflection or an author-supplied schema), and exposes
the response to the existing matcher/extractor engine. The central design choice —
borrowed directly from
grpcurl's model and from @matheusalbarello's proposal in#6426 — is that template authors never touch the protobuf wire format.
Problem statement
coverage stops at the transports listed above.
codeprotocol invokinggrpcurlin a shell. This:-codeflag and a signed template (codetemplates executearbitrary local commands, so they are gated and must be signed by design — see
Background);
grpcurlbeing installed on the scanning host;address gRPC status codes, response fields, or trailers.
push
.proto/protobuf concerns into YAML templates, which is unworkable fortemplate authors. This is the core engineering challenge first called out by
@zxelzy in #6426.
Goals
grpctemplate block for unary RPC calls.protobuf wire bytes.
reflection so the common case needs no
.proto.the gRPC response as a DSL map.
id-based request chaining, dynamicvalues, and the
{{ }}variable/payload system.idiomatic and reviewable.
Non-goals
scope for v1. The syntax is designed to extend to streaming later (see
Rollout plan).
gRPC-over-HTTP/2; gRPC-Web endpoints are only detectable via the
content_typepart,and custom/non-protobuf codecs are unsupported.
evans-style interactive shell..protofiles; the protocol consumes schemas, it doesnot author them.
-codegate, or matcher/extractorsemantics beyond adding gRPC-specific response parts.
.protoat build time; all schema handling is runtime(reflection, runtime
.protocompilation, or a precompiled descriptor set).(
pkg/templates/cluster.go) only groups single HTTP/DNS/TLS requests, and gRPCrequests are method-specific (distinct method + JSON body + descriptor source), so
identical-request collisions are rare. Revisit in the streaming follow-up.
pre-build a
FileDescriptorSetwithbuf build/protocand reference it viadescriptor-set;descriptor-setcould later accept a URL. This keeps the"reproducible, offline runs" goal intact and avoids a new network-trust surface.
Terms
Server reflection — the optional gRPC service (
grpc.reflection.v1.ServerReflection,or the older
v1alpha) a server may expose so clients can discover service,method, and message descriptors at runtime. This is how
grpcurl/evansoperatewithout a local
.proto.Descriptor — the protobuf schema (
FileDescriptor/MethodDescriptor/MessageDescriptor) needed to marshal a JSON request into a protobuf message andunmarshal the response back to JSON.
Descriptor source — where Nuclei obtains descriptors: server reflection, a
.protosource file compiled at runtime, or a precompiledFileDescriptorSet.Fully-qualified method —
package.Service/Method, e.g.helloworld.Greeter/SayHello.Response part — a named key in the response DSL map that a matcher/extractor
can address via
part:(e.g.body,status_code).Background and current behavior
No native gRPC protocol today
Confirmed by @adilburaksen in #6426: the built-in protocols cover
http/tcp/dns/ssl/websocket/javascript (and file, whois, headless, code), but there
is no gRPC DSL. Each protocol implements the
Requestinterface inpkg/protocols/protocols.go(Compile,Requests,GetID,Match,Extract,ExecuteWithResults,MakeResultEvent,MakeResultEventItem,GetCompiledOperators,Type).Current workaround:
codeprotocol + grpcurlDemonstrated by @matheusalbarello in #6426:
Run with
nuclei -code -t grpc.yaml -u target:50051. As noted in the thread,-codeis gated behind a flag and requires template signing by design: unsigned
codetemplates are rejected during loading regardless of the flag, because the
codeprotocol executes arbitrary local commands (enforced in
pkg/catalog/loader/loader.go; the-codeflag is registered incmd/nuclei/main.go). A network protocol such as gRPC does not execute localcode, so it should load unrestricted like HTTP/network (see
Security considerations).
Existing protocol architecture (grounding)
A new protocol is wired in by:
ProtocolTypevalue and string mapping inpkg/templates/types/types.go;Templatestruct and registering it throughpkg/templates/templates.go(Type(),validateAllRequestIDs,hasMultipleRequests,addRequestsToQueue) andpkg/templates/compile.go(
Requests(),updateRequestOptions,compileProtocolRequests), plus aHas*Requesthelper inpkg/templates/templates_utils.go;Requestinterface in a newpkg/protocols/grpcpackage.The simplest existing protocol to model the new package on is whois
(
pkg/protocols/whois/whois.go): it embedsoperators.Operatorsinline, builds adatamap of response fields, and delegates matching toprotocols.MakeDefaultMatchFunc/MakeDefaultExtractFunc. The gRPC protocolfollows the same shape.
Proposal
Design principles
grpc:is a list of requests; operators(
matchers/extractors) are embedded inline;idenables request chaining;{{ }}variables andpayloadswork as in other protocols.reflection so the common case needs no
.proto; allowprotoanddescriptor-setas fallbacks for reflection-disabled targets. (Adapted from@zxelzy and @matheusalbarello, #6426; extended with
descriptor-set.)to protobuf via the resolved descriptor; responses are marshaled back to JSON
for matching. (Adopted from @matheusalbarello / the grpcurl model, #6426.)
Template syntax (the
grpcblock)Canonical unary call using server reflection:
Schema acquisition model (reflection-first, three sources)
Exactly one descriptor source resolves per request. Reflection is the default
(the zero-config common case needs no
.proto— this is the "reflection-first"ergonomic). An explicitly set schema source overrides reflection, and if more
than one is set the precedence is
descriptor-set>proto> reflection(consistent with Precedence and resolution rules).
reflectionis a tri-state*bool: omitted ⇒ defaulttrue, while an explicitreflection: falsedisables it (and, with noproto/descriptor-set, is aconfiguration error). This mirrors
dns.Request.Recursion.descriptor-setFileDescriptorSet(most reproducible); wins over the others.protoproto,import-pathsdescriptor-setreflection: true(default)If reflection is used but the target does not expose it, the request fails
with a clear, matchable error rather than silently degrading.
Request body model (JSON → protobuf)
requestis a JSON object string. After{{ }}evaluation it is unmarshaledinto a dynamic protobuf message using the resolved input descriptor.
oneof,bytesas base64, well-known types such asgoogle.protobuf.Timestamp).This is the main reason JSON is preferred over a YAML payload map (see
Alternatives considered).
requestparticipates in payload fuzzing:{{placeholder}}tokens are filledfrom
payloadswith the chosenattacktype, enabling per-field fuzzing.Serialization (protojson) options
JSON ⇄ protobuf conversion uses
protojsonwith fixed, documented options sotemplates behave deterministically:
DiscardUnknown: false— an unknown JSON field is an error,which catches typos in template field names instead of silently dropping them.
body):UseProtoNames: true(emitsnake_caseproto fieldnames so matchers stay stable across runs) and
EmitUnpopulated: false(omitzero-value fields). Enums marshal to their string name,
bytesas base64, andwell-known types (
Timestamp/Duration/Any) use their canonical JSON forms.Response model and matcher/extractor parts
The response is exposed as a DSL map. Matchers/extractors select a key via
part:(default
body).Extractdelegates toprotocols.MakeDefaultExtractFunc, butMatchis implemented directly (modeled onhttp/dnsoperators.go), becausethe
statusmatcher type is not handled byprotocols.MakeDefaultMatchFunc—that helper only covers
word/regex/binary/size/dsl/xpath. The customMatchadds amatchers.StatusMatchercase that callsmatcher.MatchStatusCodeagainst the numeric gRPC code; all other matcher types delegate to the default func.
status_codeis stored in the data map as anint(mirroring network'sgetStatusCode), not a string. Copying whois verbatim — which has no status matcher —would make
type: statussilently never match.partkeybodyrawfield-number:wire-type:valuewhen no descriptor resolves (field numbers/primitive values only; no field names)raw_bodystatus_code0= OK …16)statusOK,PERMISSION_DENIED,UNAUTHENTICATED) for name-based matchingstatus_messagestatus_details/error_detailsgrpc-status-details-bintrailer decoded togoogle.rpc.StatusJSON (code + message +detailsAnylist)errorcontent_typecontent-type(application/grpc,application/grpc-web+proto,application/grpc-web-text, …) — lets a template positively flag a gRPC-Web endpointheaderstrailersrtthost/method/requestThe numeric
status_codeis matched with the existingstatusmatcher type (via thecustom
Matchabove); the symbolicstatuspart is forword/dslmatching by name.Field-name matching on
bodyrequires a resolved descriptor; when none is available(reflection off and no
proto/descriptor-set), authors match field numbers andprimitive values on
raw, or bytes onraw_body(seeSecurity considerations).
The default
partisbody. Because the sharedMakeDefaultMatchFunc(and the extracthelper) default an empty
parttoresponse, notbody, the data map exposes theresponse JSON under both
bodyandresponse, and the customMatchnormalizes anomitted
parttobody— sopart: bodyand an omittedpartstay equivalent.Transport and metadata
plaintext: truedisables TLS. When absent, the connection uses TLS (gRPC'sdefault); a
tlsblock configuresserver-name(SNI),insecure, and mTLScert/key/ca. (Adopted from @matheusalbarello, #6426.)metadatais a gRPC request-metadata multimap (map[string][]string; a key mayrepeat), with
{{ }}support. Keys ending in-bincarry binary metadata asbase64 (the gRPC convention). A scalar value is accepted as shorthand for a
single-element list. This maps to
google.golang.org/grpc/metadata.MD.timeoutoverrides the global per-request timeout.host, TLS-vs-plaintextmode,
server-name,insecure, the client cert/key/ca identity, and any authorityoverride — a connection is never reused across a differing TLS posture.
Field reference
idhost{{Hostname}}host:port)methodpackage.Service/Methodrequest{}reflectiontrue(when omitted)falsedisables it (backed by a tri-state*boolinternally — see Schema acquisition model)proto.protosource path (catalog-relative)import-pathsprotodescriptor-setFileDescriptorSetpathplaintextfalsetlsserver-name,insecure, mTLScert/key/cametadata-bin-suffixed keys carry base64 binary metadata. A scalar is accepted as shorthand for a one-element listtimeoutmatchers/extractorsImplementation sketch
Backing Go type and engine wiring — click to expand
Following the whois convention (
pkg/protocols/whois/whois.go):Type()returns a newtemplateTypes.GRPCProtocol;Extract/MakeResultEventdelegate to the
protocols.MakeDefault*helpers, butMatchis custom (seeResponse model — the default match func
has no
StatusMatchercase). Every field carries a yamldoc-go// description:doc-comment (as
whois.godoes), since SYNTAX-REFERENCE/jsonschema generation readsthose comments, not the
jsonschema:tags (those only feed the JSON-schemareflector).
Engine integration points:
pkg/templates/types/types.go— addGRPCProtocolto the enum andprotocolMappings("grpc").pkg/templates/templates.go— addRequestsGRPC []*grpc.Requestfield; handleit in
Type(),validateAllRequestIDs,hasMultipleRequests,addRequestsToQueue; add the import.pkg/templates/templates_utils.go— addHasGRPCRequest.pkg/templates/compile.go— include inRequests(),updateRequestOptions,compileProtocolRequests.pkg/tmplexec/flow/flow_executor.go— addcase templateTypes.GRPCProtocoltothe
NewFlowExecutortype switch. Itsdefaultbranch returns"invalid request type", so an unregistered gRPC type hard-errors everyflow/multi-protocol template, not only
flow:ones.pkg/protocols/grpc/— new package implementing theRequestinterface, modeledon
pkg/protocols/whoisfor structure, but with a customMatch(likehttp/dns) and network-style payload/variable handling (whois has none).pkg/templates/cluster.go) is a non-goal for v1.Examples
(a) Reflection-disabled target —
.protofallback(b) TLS + metadata + status-based authorization check
(c) Message-field fuzzing via
payloads(d) Unary request chaining (
id+ extractor + metadata)Precedence and resolution rules
methodis required and must be fully qualified (package.Service/Method).descriptor-setis set it wins;else if
protois set it is compiled at runtime; else reflection is used.reflection: falsewith neitherprotonordescriptor-setis aconfiguration error.
plaintext: trueand atlsblock are mutually exclusive;specifying both is an error.
hostdefaults to{{Hostname}}(which carrieshost:port); an explicithostoverrides it.requestdefaults to an empty message ({}) when omitted.partisbody.request. A call with noresolved descriptor is possible only when the request is empty (an empty protobuf
message is zero bytes regardless of its type); the response is then exposed only via
the schemaless
raw/raw_bodyparts. Schemaless generation of non-empty requests isout of scope (see Non-goals / Security considerations).
Author guidance
reflection: true(the default) — it requires no local schema and mirrorshow
grpcurl/evanswork.descriptor-setfor reproducible, offline runs (build it withprotoc --descriptor_set_out=orbuf build -o image.binpb).proto+import-pathswhen you only have source.protofiles.plaintext: truefor development/cleartext endpoints; otherwise configuretls.match on
status_code/errorrather thanbody(seeSecurity considerations for why body inspection
needs a schema).
serving the method; prefer a pinned
descriptor-set/protowhen schema stabilitymatters.
Validation and warning policy
Recommended warnings/errors at compile time:
methodmissing or not fully qualified (package.Service/Method; nogrpc://scheme).
reflection: falsewith neitherprotonordescriptor-set.plaintext: trueand atlsblock present.requestis not valid JSON after{{ }}evaluation.{{ }}/payload substitutionhappens on the JSON string before unmarshaling, so values interpolated into JSON
string positions must be JSON-escaped. The recommended policy is to wrap such
values with the
to_jsonDSL helper — e.g.{"q": {{to_json(injection)}}}, whichemits a quoted, fully escaped JSON string — instead of a bare
"{{injection}}", whichbreaks when a payload contains
"or\. As a backstop the engine validates thepost-interpolation
requestas JSON, and a permutation that yields invalid JSON failswith a matchable error rather than being silently skipped.
proto/descriptor-setpath not found in the catalog.client_streaming/server_streamingflags are checked; any streaming method isrejected in v1 with a clear, matchable error (unary-only — see
Non-goals). Concretely:
if md.IsStreamingClient() || md.IsStreamingServer() → error.Resolved design questions (previously open):
statusmatcher type, handled by theprotocol's custom
Match(not a newgrpc-statustype); a symbolicstatuspart is also exposed for name-based matching. See
Response model.
Future work: streaming (deferred)
Streaming RPCs are a v1 non-goal; adding them later touches Nuclei's
"one request → one/few response events" model, so the v1 syntax reserves these
extension points now to stay forward-compatible:
stream: trueandstream-mode: server|client|bidiopt a request into streaming.requestaccepts a JSON array of messages (client/bidi); a single object staysvalid shorthand for unary — so today's
requestsyntax does not have to change.messages(array of decoded messages),message(current message),
message_count,first_message,last_message. The final gRPCstatus still arrives in
trailers/status_code, so a stream can have matchingmessages and a non-OK final status — the two must be evaluated independently.
max-messages,max-duration,idle-timeout,max-bytes. Aserver stream may never end, and unbounded reads would stall scans or exhaust memory.
stop-on-match/ half-close policy must be defined. These, plus bidi concurrency(concurrent send/receive loops, cancellation, deadlines), are why bidirectional
streaming is expected to warrant its own RFC.
Staged rollout: v1 unary → v1.1 server-streaming (single request → many responses, the
lowest-complexity case) → client-streaming → bidirectional (separate RFC). Reflection
enumeration — itself a bidi-streaming API, handled internally today — could surface as a
built-in action rather than a raw streaming call, e.g.
action: list-services/describe, so authors never implementServerReflectionInfothemselves. Streaming wouldalso need its own response parts (
message/messages/message_count, and afinal_status_codedistinct from unarystatus_code, since the final status arrives intrailers) and a matcher scope (
per-message/aggregate/until-match) withdedicated bounds (
max-messages,max-duration,idle-timeout,first-message-timeout).Security considerations
No
-grpcgate and no mandatory signing. The-codeflag and templatesigning exist specifically because the
codeprotocol executes arbitrary localcommands (enforced in
pkg/catalog/loader/loader.go). gRPC only makes outboundnetwork calls, like HTTP and network; it should load unrestricted and adopt those
protocols' posture, not the
codeprotocol's.Loading a schema executes no code. Runtime
.protocompilation(
protocompile) only parses source — it does not invokeprotoc, plugins, orcodegen — and a
descriptor-setis inert data. This reinforces why no signing isneeded: unlike
code, no author-supplied input is executed.Validate schema-file paths.
proto,import-paths,descriptor-set, and themTLS
cert/key/capaths are catalog-relative and MUST be confined to thetemplate/catalog root — reuse
Options.GetValidAbsPath/IsPathWithinDirectory(
pkg/utils/filepath), which canonicalizes symlinks and rejects..-escapes;absolute paths and traversal outside the root are refused. A schema file is not
executed, but it changes how requests/responses are (de)serialized, so when a
signed template references an external schema file that file must fall inside the
template's signing/provenance scope — otherwise a verified template could be silently
re-pointed at a different schema.
Treat reflection/descriptor input as untrusted. Descriptors returned by a
target's reflection service (and author-supplied
.proto/descriptor-set) areattacker- or third-party-controlled, so the resolver MUST enforce concrete bounds
rather than parsing unboundedly:
files, max symbols, and max message nesting depth;
Resolved descriptors are cached per host+method within a scan (with TTL/eviction) to
avoid repeated reflection round-trips.
Reflection is an information-exposure surface. Many production servers disable
it on purpose. The protocol must support reflection-disabled targets via
proto/descriptor-setand fail with a clear, matchable error — never a silentskip that reads as "not vulnerable."
No schema ⇒ field-number matching only. The protobuf wire format carries field
numbers and wire types but not field names. Without a descriptor, field-name
matchers on
bodycannot be satisfied, but the response is still decodedschemalessly (field numbers and approximate values, à la
protoc --decode_raw) andexposed via the
raw/raw_bodyparts (seeResponse model), so authors can still
match field numbers and primitive values. Schemaless request generation remains
out of scope.
TLS verification is on by default. Certificates are verified unless the author
sets
tls.insecure: trueexplicitly, andplaintext: truemust be an explicitopt-in for cleartext targets. mTLS material (
tls.cert/tls.key) andmetadatasecrets (e.g.
authorization) support{{ }}interpolation so they are nothard-coded in shared templates.
Destination ownership. A request dials the author-declared
host(default{{Hostname}}from scan input), consistent with other protocols; the sametarget-resolution and SSRF considerations as network/HTTP apply.
Backward compatibility
grpctemplate block. No existingtemplate changes behavior.
code+grpcurlworkaround continues to work for authors who prefer it.-codegate, or operator semantics; only newgRPC-specific response parts are introduced.
Alternatives considered
A. Keep using the
code+grpcurlworkaroundProposed as the interim approach by @matheusalbarello (#6426). Rejected as the
end state: requires the
-codegate and signed templates, depends ongrpcurlon the host, and exposes only unstructured stdout to operators.
B.
service:+method:split with a YAMLpayload:mapProposed by @zxelzy (#6426):
Partially adopted (reflection-first and the
pkg/protocols/grpcintegration comefrom this proposal), but the single
method: service/methodstring is preferredbecause it matches reflection lookup keys and reduces author error, and a JSON
requestbody is preferred over a YAMLpayloadmap because YAML cannot cleanlyexpress
oneof,bytes, or well-known types.C. Protobuf wire bytes directly in YAML
Rejected: unworkable for authors and brittle across schema changes; defeats the
purpose of a declarative template.
D. Reimplement HTTP/2 + protobuf in the JavaScript runtime
Considered (the JS
netlibrary exists). Rejected: gRPC is HTTP/2 + protobuf, andreimplementing framing and protobuf by hand in JS is error-prone and slow. As
@matheusalbarello noted (#6426), shelling out or building a native protocol is
the pragmatic path.
Prior art
How existing DAST and API-security tools test gRPC — and how they handle the
schema problem when no
.protois available — was surveyed with two independentresearch passes that were then cross-verified: one using adversarial multi-vote
verification (high bar, narrow confirmed set), the other citation-backed breadth
across more vendors (wider coverage, lower per-claim assurance). The core
reflection-first conclusions below were confirmed by both passes; the broader
commercial-vendor inventory rests on the single citation-backed pass and is flagged
where confidence is lower. All sources are listed at the end of this section.
The landscape splits into two camps:
grpcurl,Evans, and
StackHawk HawkScan
query gRPC server reflection at runtime and fall back to author-supplied
.proto/FileDescriptorSet. HawkScan is the closest DAST precedent (reflection bydefault, descriptor-set fallback; its gRPC support is Beta);
grpcurlis thereference UX for the JSON-through-descriptor model this RFC adopts. This is exactly
the table-stakes pattern proposed here. Note that server reflection is frequently
disabled in production for security, so on real targets the
.proto/descriptor-setfallback is often the de-facto primary path, not an afterthought (see
Security considerations).
(blackboxprotobuf/
bbpb,grpc-pentest-suite,
bRPC-Web) and the
OWASP ZAP gRPC add-on
decode the protobuf wire format with no schema, emitting field-number-keyed output
(field names are absent from the wire). As of late 2025 these are scoped almost
entirely to gRPC-Web, not native gRPC-over-HTTP/2: no native-gRPC Burp extension
was found (Burp supports the HTTP/2 transport, but appears to lack native gRPC
message decoding).
Most commercial API-security platforms do not offer first-class gRPC DAST:
Bright, APIsec, Rapid7 InsightAppSec, and 42Crunch take contract/schema inputs
(OpenAPI/Swagger/Postman/WSDL/GraphQL, varying by tool) rather than gRPC descriptors;
Wallarm surfaces gRPC in runtime traffic discovery rather than schema-based testing.
(Akto's own docs additionally claim gRPC security testing and fuzzing, but that is an
unverified vendor claim.) Dedicated fuzzers
(Viasat gRPC-Fuzzer, Microsoft RESTler,
boofuzz) are either
.proto-required-and-unary-only or not gRPC-aware.Where this design sits relative to the surveyed state of the art:
.proto/descriptor-set + JSON-body marshalingrawpart (field numbers/values); request-side schemaless out of scopecontent_typepart; full gRPC-Web transport deferred (native gRPC-over-HTTP/2 only in v1)The survey also confirms the table-stakes pattern is buildable with mature Go
libraries —
google.golang.org/protobuf/dynamicpb+protojsonwith a reflectionclient (the older
jhump/protoreflect/dynamicis now deprecated in favor of these),which is why the Dependencies below use
google.golang.org/protobuf'sdynamicpb/protojson. These gaps are typical (no surveyed tool combinesreflection-first, descriptor upload, schemaless fallback, gRPC-Web, and full
streaming), but they are real versus the union of the state of the art: the streaming
gap is tracked in the Rollout plan; schemaless decode is addressed
response-side via the
rawpart, and gRPC-Web is detectable viacontent_typewithfull transport support deferred.
Sources (prior-art survey):
dynamicpb/protojson) — https://github.com/jhump/protoreflectDependencies
A native implementation introduces new direct dependencies (none of these are
currently direct deps;
google.golang.org/protobufis present only as an indirectdependency, and HTTP/2 is already available via
golang.org/x/net):google.golang.org/grpc— the gRPC client.google.golang.org/protobuf— descriptors,dynamicpb,protojson.github.com/fullstorydev/grpcurlalreadyunifies the three descriptor sources (
DescriptorSourceFromServer,DescriptorSourceFromProtoFiles,DescriptorSourceFromProtoSets) plusInvokeRPC; for runtime.protocompilation,github.com/bufbuild/protocompile.Rollout plan
model.
pkg/protocols/grpcpackage (unary) modeled onpkg/protocols/whois,plus the engine integration points.
protoanddescriptor-setresolvers.internal/tests/integrationwith a local gRPC test server.// description:doc-comments to everygrpcfield, then runmake docs && make syntax-docsand commit the regeneratedpkg/templates/templates_doc.go,SYNTAX-REFERENCE.md, andnuclei-jsonschema.jsonin the same PR (generation reads the doc-comments, not thejsonschema:tags).Acceptance criteria
local
.proto.protoordescriptor-set.body,status_code,status_message, andmetadata.
payloadsfuzz request message fields;idchaining passes extracted valuesbetween gRPC requests.
-codeand without signing.Integration tests (against a local gRPC test server) should cover at least:
proto, and viadescriptor-set;descriptor-set>proto> reflection precedence when several are set;reflection: falsewith no schema source → configuration error;methodformat; streaming method rejected (unary-only);plaintext: true+tlsblock → conflict error;statusmatcher on the numeric code; extractor defaultpart;body/responsealias equivalence;
status_details/ trailers (rich error) decode;metadatainjection (including a-binkey) and TLSserver-namehandling;References and attribution
Originating discussion:
Is gRPC implement in nuclei engine? — projectdiscovery/discussions#6426
Contributor attribution (from #6426):
pkg/protocolsProtocol/Requestinterfaces; code protocol as interim"pkg/protocols/grpcpackage +RequestsGRPCon the Template struct; reflection-vs-.protoas the core serialization question; "open an RFC first"service/method;plaintext/tls; optionalproto;code+grpcurl interim templateExtensions beyond the discussion (added in this RFC):
descriptor-setas athird schema source; explicit response-part model (
status_code,status_message,trailers,metadata,rtt);metadatarequest headers;payloads-based fieldfuzzing;
id-based request chaining; security rationale for no gate/signing; theno-schema raw-decode limitation; the engine-integration checklist.
Codebase references (current
dev):pkg/protocols/protocols.go(Request interface),pkg/protocols/whois/whois.go(skeleton),
pkg/templates/types/types.go(ProtocolType),pkg/templates/templates.go,pkg/templates/compile.go,pkg/templates/templates_utils.go(registration),pkg/catalog/loader/loader.goandcmd/nuclei/main.go(code gating/signing scope).External references:
github.com/fullstorydev/grpcurl,github.com/bufbuild/protocompile,google.golang.org/grpc,google.golang.org/protobuf(dynamicpb,protojson,reflect/protodesc).Beta Was this translation helpful? Give feedback.
All reactions