Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions skills/appsec/api-security/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,25 @@ Deeply nested or highly complex queries can exhaust server resources (API4:2023)
- **Maximum query depth** (e.g., 5-10 levels depending on schema complexity).
- **Query complexity scoring** -- assign cost weights to fields and reject queries exceeding a threshold.
- **Batch query limits** -- restrict the number of queries in a single request (query batching/aliasing).
- **Alias limits** -- cap aliases globally and for sensitive resolvers so one HTTP request cannot hide many expensive or credential-sensitive operations.
- **Persisted-query enforcement** -- reject unknown hashes and raw query documents when production policy is persisted-query-only.

### GraphQL Operation-Control Evidence Gates

Do not report GraphQL resource-consumption risk from query shape alone. Preserve the enforcement evidence that proves whether a query is bounded or exploitable:

| Evidence Item | Safe Signal | Finding When Missing |
|---|---|---|
| Operation count per HTTP request | JSON batch arrays disabled or capped at 1 unless explicitly justified | Batched operations can bypass endpoint rate limits |
| Alias count | Global alias cap and per-sensitive-resolver cap documented | Alias fan-out can multiply resolver calls inside one request |
| Depth limit | Enforced maximum depth with production config path or gateway policy | Nested traversal can exhaust CPU, DB, or downstream APIs |
| Complexity budget | Enforced request budget with rejection behavior and logs | Expensive documents can execute without cost accounting |
| Resolver cost overrides | High-fan-out fields such as search, exports, reports, and connections have calibrated costs | Default field cost underprices DB fan-out or third-party calls |
| Persisted query policy | Unknown hashes rejected and raw documents blocked in persisted-only environments | Attackers can submit arbitrary expensive documents |
| Subscription limits | Per-connection subscription count, lifetime, and event fan-out caps | Long-lived operations bypass per-request accounting |
| Federation parity | Router and subgraphs enforce compatible auth and cost controls | Subgraphs can bypass router-only limits or authorization |

If a benign query is bounded by these controls, record the controls and avoid escalating it as unrestricted consumption. If a control is claimed but no config, test, log, or gateway policy evidence exists, report the missing evidence rather than assuming protection.

### Field-Level Authorization

Expand All @@ -199,6 +218,30 @@ Unlike REST, where authorization can be enforced per endpoint, GraphQL requires

**Mitigation:** Count aliased operations against rate limits. Limit the number of aliases per request.

### Persisted Query Bypass

```yaml
prod_policy:
persisted_queries_required: true
observed_behavior:
unknown_sha256_hash: accepted_raw_query
introspection: disabled
```

**Mitigation:** In persisted-query-only production environments, reject unknown hashes and raw query documents before parsing or executing the document. Disabling introspection is not sufficient if arbitrary query bodies are still accepted.

### Resolver Cost Underpricing

```yaml
complexity_plugin: enabled
resolver_costs:
User.orders: default_1
Search.results: default_1
Report.exportUrl: default_1
```

**Mitigation:** Assign explicit costs to resolvers that fan out to databases, exports, third-party APIs, or nested connections. Validate the cost matrix with representative production queries and logs.

---

## Common Pitfalls
Expand Down