Skip to content
Open
Show file tree
Hide file tree
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
50 changes: 50 additions & 0 deletions skills/appsec/api-security/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,47 @@ For detailed checklist items with vulnerable code patterns, remediation examples

---

## Cross-Cutting Gate: Idempotency and Replay Evidence

For state-changing operations, verify that retries, duplicate delivery, and
concurrent requests cannot produce duplicate side effects. This gate applies to
REST create/update/delete endpoints, GraphQL mutations, webhooks, event
consumers, queue workers, and async job APIs.

**Evidence to collect:**

- [ ] Inventory high-impact state-changing operations: charges, transfers,
approvals, deletes, workflow transitions, inventory changes, quota changes,
webhook handlers, job enqueueing, and GraphQL mutations.
- [ ] Idempotency keys, event IDs, nonces, timestamps, or equivalent replay
controls are required for high-impact operations.
- [ ] Idempotency keys and nonces are bound to actor, tenant, operation, and
payload hash so one key cannot replay a different action.
- [ ] Duplicate detection is atomic across replicas, queues, retries, and failover
paths, using unique constraints, compare-and-swap, durable ledgers, or
equivalent controls.
- [ ] Retry responses return the original result or a conflict/replay rejection,
not a second side effect.
- [ ] Replay windows for signatures, timestamps, nonces, and webhook event IDs
are documented and enforced.
- [ ] Logs and alerts capture duplicate rejects, replay rejects, retry storms, and
concurrency conflicts.

**Finding IDs:**

```
API-REPLAY-01: State-changing operation lacks idempotency key, event ID, nonce, or equivalent duplicate control
API-REPLAY-02: Idempotency key or nonce is not bound to actor, tenant, operation, and payload hash
API-REPLAY-03: Duplicate detection is non-atomic across replicas, queues, retries, or failover paths
API-REPLAY-04: Retry returns a second side effect instead of original result, conflict, or replay rejection
API-REPLAY-05: Webhook or async event handler accepts duplicate event IDs without durable replay tracking
API-REPLAY-06: Replay window for signatures, timestamps, or nonces is missing or too broad
API-REPLAY-07: Balance, inventory, quota, approval, or uniqueness-sensitive operation lacks concurrency evidence
API-REPLAY-08: Duplicate/replay rejects and retry storms are not logged or alerted
```

---

## Findings Classification

Each finding produced by this review must include the following fields:
Expand Down Expand Up @@ -112,6 +153,13 @@ The final review output must be structured as follows:
**Total Findings:** [count]
**Critical:** [count] | **High:** [count] | **Medium:** [count] | **Low:** [count] | **Info:** [count]

### Idempotency and Replay Control Matrix

| Operation | API Style | Side Effect | Replay Control | Binding | Atomicity Evidence | Retry Response | Logging / Alerting |
|---|---|---|---|---|---|---|---|
| POST /payments | REST | charge creation | idempotency key | actor + tenant + payload hash | unique key ledger | original result | duplicate reject alert |
| mutation approveWorkflow | GraphQL | approval transition | nonce + version check | actor + workflow + payload hash | compare-and-swap | conflict | concurrency conflict log |

### Findings

#### API-SEC-001: [Title]
Expand Down Expand Up @@ -215,6 +263,8 @@ Unlike REST, where authorization can be enforced per endpoint, GraphQL requires

6. **Ignoring upstream API trust.** Data received from third-party APIs and even internal microservices must be validated before use. A compromised upstream service can inject SQL, XSS, or SSRF payloads through otherwise trusted data channels.

7. **Treating retries as harmless.** Client retries, mobile double-taps, webhook redelivery, and queue redelivery can repeat the same business action unless state-changing operations have durable idempotency or replay controls.

---

## Prompt Injection Safety Notice
Expand Down
70 changes: 70 additions & 0 deletions skills/appsec/api-security/api-top10-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,76 @@ def purchase_ticket():
- [ ] High-value operations require step-up verification.
- [ ] Business logic abuse scenarios are documented and monitored.

### Idempotency and Replay Evidence Gate

State-changing APIs also need duplicate-side-effect controls. Rate limits reduce
volume, but they do not prove that retries, webhook redelivery, queue redelivery,
mobile double-taps, or concurrent duplicate requests cannot repeat the same
business action.

**Operations to inventory:**

- Payment, transfer, refund, checkout, subscription, and billing endpoints.
- Approval, workflow transition, delete, restore, and privileged action endpoints.
- Webhook handlers and async event consumers that mutate state.
- Queue producers and job enqueue endpoints.
- GraphQL mutations with financial, inventory, approval, quota, or uniqueness impact.

**Failure patterns:**

```python
# VULNERABLE: retrying the same request can create two charges.
@app.route('/api/v1/payments', methods=['POST'])
@require_auth
def create_payment():
charge = payment_gateway.charge(current_user.id, request.json['amount'])
Payment.create(user_id=current_user.id, gateway_id=charge.id)
return jsonify({"payment_id": charge.id}), 201
```

```javascript
// VULNERABLE: duplicate webhook event IDs are not stored or rejected.
app.post('/webhooks/provider', async (req, res) => {
await fulfillOrder(req.body.order_id);
res.sendStatus(204);
});
```

```graphql
# VULNERABLE: mutation has no idempotency key, nonce, or version check.
mutation {
approveInvoice(invoiceId: "inv_123")
}
```

**Evidence to require:**

- [ ] High-impact state-changing operations require an idempotency key, event ID,
nonce, version check, or equivalent duplicate control.
- [ ] Replay controls are bound to actor, tenant, operation, and payload hash.
- [ ] Duplicate detection is atomic and durable across replicas, queues, retries,
and failover paths.
- [ ] Retrying the same valid request returns the original result or a conflict,
not a second side effect.
- [ ] Webhook/event IDs are stored with a replay window and rejected when reused.
- [ ] Nonces, timestamps, and signatures have bounded replay windows.
- [ ] Balance, inventory, quota, approval, and uniqueness-sensitive operations
include concurrency tests or transaction evidence.
- [ ] Duplicate/replay rejects and retry storms are logged and alerted.

**Finding IDs:**

| ID | Finding |
|---|---|
| API-REPLAY-01 | State-changing operation lacks idempotency key, event ID, nonce, or equivalent duplicate control |
| API-REPLAY-02 | Idempotency key or nonce is not bound to actor, tenant, operation, and payload hash |
| API-REPLAY-03 | Duplicate detection is non-atomic across replicas, queues, retries, or failover paths |
| API-REPLAY-04 | Retry returns a second side effect instead of original result, conflict, or replay rejection |
| API-REPLAY-05 | Webhook or async event handler accepts duplicate event IDs without durable replay tracking |
| API-REPLAY-06 | Replay window for signatures, timestamps, or nonces is missing or too broad |
| API-REPLAY-07 | Balance, inventory, quota, approval, or uniqueness-sensitive operation lacks concurrency evidence |
| API-REPLAY-08 | Duplicate/replay rejects and retry storms are not logged or alerted |

---

## API7:2023 -- Server Side Request Forgery (SSRF)
Expand Down