본문으로 건너뛰기
cccskills
무료GitHub에 공개

rpc-messaging-and-webhooks

Use when the diff adds or changes a gRPC service or interceptor, a GraphQL resolver or subscription, a protobuf/Thrift schema, a queue or pub/sub producer or consumer, an event handler or an inbound webhook - peer identity vs claimed principal, interceptor gaps, per-item and stream authorization, webhook signatures, untrusted producers, enum defaults, replay, duplicate delivery and ordering

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

연동 도구Cloudflare
설치 방법 보기

포함된 파일(1)

  • SKILL.md8.0 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

RPC, Messaging and Webhooks

Overview

Behind the HTTP edge, services talk through RPC calls, queues and callbacks, and two beliefs keep failing there: "it is internal, so it is authenticated" and "it passed the schema, so it is safe". A schema proves a message's shape — not who sent it, which tenant it may touch, whether it was already processed, or whether it is still current.

Core principle: at every hop, name the authenticated peer and show how it becomes the principal the handler authorizes. A field inside the message that names a user or tenant is a claim, not an identity.

1. gRPC Interceptors and Method Coverage (CWE-306, CWE-862)

// ❌ only unary calls are authenticated; every streaming method is open
srv := grpc.NewServer(grpc.UnaryInterceptor(authUnary))

// ✅ both kinds, and the skip list is exact method names, not prefixes
srv := grpc.NewServer(
	grpc.ChainUnaryInterceptor(authUnary),
	grpc.ChainStreamInterceptor(authStream),
)

Also: a skip list matched with strings.HasPrefix(info.FullMethod, "/pkg.Health") that also matches /pkg.HealthAdmin/…; server reflection registered on a public listener next to unauthenticated methods; grpc-gateway or Connect transcoding that reaches the same handler through an HTTP route the interceptor does not see; identity read from metadata such as x-user-id that any client can send.

2. Per-Item and Streaming Authorization

A stream, subscription or batch is authorized once, then later items name different resources:

  • a bidirectional stream checks the first message's project and trusts the rest;
  • a GraphQL subscription authorized at connect keeps delivering after the user's role is revoked;
  • a batch RPC with repeated string ids checks ids[0];
  • a WebSocket that subscribes by channel name builds the channel from client input ("org." + msg.org).

Re-check where the scope can change, and bind a subscription to the principal and resources it started with.

3. GraphQL Specifics

  • Authorization in a field resolver, not only on the root query: the parent was checked, the nested resolver loads by raw id (access-control-and-idor §4).
  • A directive or middleware applied to Query but not to Mutation or Subscription.
  • Node or id lookups (node(id:)) that resolve any type by global id without the type's own check.
  • Introspection enabled is not a finding by itself; query depth and cost limits are availability (excluded).

4. Inbound Webhooks (CWE-345, CWE-347)

// ❌ JSON re-serialized before verifying; tenant chosen by the body, then its secret used
const evt = JSON.parse(req.body);
const secret = await secrets.forAccount(evt.account_id);
if (sign(JSON.stringify(evt), secret) !== req.header("X-Signature")) return res.sendStatus(401);

// ✅ verify the raw bytes with the secret bound to the endpoint, then parse
const secret = await secrets.forEndpoint(req.params.endpointId);
if (!timingSafeEqualHex(hmac(req.rawBody, secret), req.header("X-Signature"))) return res.sendStatus(401);
const evt = JSON.parse(req.rawBody);
if (evt.account_id !== endpoint.accountId) return res.sendStatus(403);
  • Choose the secret before trusting the body. When the body's account id selects the verification secret, an attacker signs with their own tenant's secret and names the victim's account.
  • Verify the raw request bytes; re-serialized JSON breaks honest signatures and tempts a fallback that skips verification.
  • Act only after verification; reject a missing signature instead of treating it as "unsigned mode".
  • Timestamp tolerance and a stored event id stop replay (authn-sessions-and-tokens §6 for the basic rules).
  • For high-value events, re-fetch the object from the provider's API instead of trusting the body's amount or status.

5. Queues, Topics and Untrusted Producers

  • The message as control plane: a consumer that grants roles, deletes data or changes billing because the body says type: "admin.grant" — while any lower-trust service, a user-facing API or a public webhook relay can publish to that topic.
  • Namespace built from input: topic, routing key, subject or consumer group derived from client text; broker wildcards (#, *, >) let one tenant subscribe to all.
  • Envelope vs payload: authorization uses a header or attribute set by a trusted router while the handler acts on the tenant in the body — or the other way round. Pick the authoritative source and reject a conflict.
  • Dead-letter and error topics: failing messages with secrets or other tenants' payloads routed to a queue a broader group can read.

6. Enum, Default and Version Confusion

// ❌ proto3 sends 0 when the field is unset — an old or careless client becomes an owner
enum Role { OWNER = 0; EDITOR = 1; VIEWER = 2; }
// ✅ zero is the meaningless, least-privileged value
enum Role { ROLE_UNSPECIFIED = 0; VIEWER = 1; EDITOR = 2; OWNER = 3; }

Also: a switch on a message type whose default branch performs the privileged handling; unknown fields kept and forwarded to a consumer that trusts them; a new field that old consumers ignore while it was meant to restrict them (readonly: true added to the producer only).

7. Replay, Duplicates and Ordering (CWE-294)

  • At-least-once delivery plus a side effect that is not idempotent: a credit applied twice, an email sent twice, an invite accepted twice. The dedupe key must be checked atomically with the effect, and scoped by tenant and operation.
  • Stale messages: a "grant" processed after a newer "revoke" because there is no version or sequence check.
  • Ack before commit loses a security-relevant event (an audit or revoke); commit before an ack that may fail repeats a mutation.
  • Correlation ids: a predictable or shared reply id lets one caller's response satisfy another's pending request.

Severity Guide

An unauthenticated RPC, stream or webhook that changes state → CRITICAL. A forged or cross-tenant event accepted by a privileged consumer → HIGH to CRITICAL. A non-idempotent duplicate with money or privilege impact → HIGH. Replay of a low-impact notification → MEDIUM at most.

Common Mistakes

  • Reporting "internal service, no auth" without showing who can reach it — and reporting it as fine for the same reason. Reachability is the question (source-visibility-needs-validation when it is not in the repository).
  • Treating a valid JSON Schema, protobuf or zod parse as an authorization check.
  • Reporting at-least-once delivery itself; the finding is the non-idempotent side effect.
  • Reporting GraphQL introspection or missing depth limits.

Red Flags

  • grpc.UnaryInterceptor with no stream interceptor; HasPrefix on FullMethod.
  • user_id, tenant_id, org or role read from RPC metadata or a message body and used for authorization.
  • A webhook handler that parses, looks up a secret by a body field, or acts before it verifies.
  • A consumer whose side effect has no idempotency key, or checks it after the write.
  • A proto enum whose zero value is a real, privileged choice.

References (names and links only)

gRPC authentication guide · OWASP GraphQL Cheat Sheet · OWASP API Security Top 10 2023 · CWE-294, 306, 345, 347, 862 · Cloudflare security-audit-skill

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

makifbaysal/tasktrooper1172026년 10월 18일 업데이트

Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

makifbaysal/tasktrooper1172026년 10월 18일 업데이트

Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

makifbaysal/tasktrooper1172026년 10월 18일 업데이트

Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

makifbaysal/tasktrooper1172026년 10월 18일 업데이트

How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

makifbaysal/tasktrooper1172026년 10월 18일 업데이트

Use when the repository keeps its alerting in code, or a person asks for alerts outside TaskTrooper - PrometheusRule YAML, a Cloud Monitoring alert policy in Terraform, a Datadog monitor, each routed to TaskTrooper's alert ingest URL so it opens an incident here

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

makifbaysal/tasktrooper1172026년 10월 18일 업데이트

makifbaysal의 스킬 모두 보기

이 스킬의 문제 신고