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
41 changes: 39 additions & 2 deletions skills/appsec/api-security/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ phase: [design, build, review]
frameworks: [OWASP-API-Security-2023, OWASP-ASVS]
difficulty: intermediate
time_estimate: "20-40min"
version: "1.0.0"
version: "1.1.0"
author: unitoneai
license: MIT
allowed-tools: Read, Grep, Glob
Expand Down Expand Up @@ -51,6 +51,31 @@ For detailed checklist items with vulnerable code patterns, remediation examples

---

## HTTP Parameter Pollution and Parser-Consistency Evidence

REST gateways, frameworks, validators, caches, signing middleware, and downstream services may choose different values when a request repeats the same query, form, path, header, or body parameter. Test duplicate-parameter handling whenever parameters influence authorization, tenancy, routing, signatures, cache keys, redirects, prices, quantities, filters, or workflow state.

**What to look for:**

```
API-HPP-01: Security-sensitive parameter accepts duplicate values without rejection or deterministic canonicalization
API-HPP-02: Gateway, WAF, validator, handler, cache, signing, or downstream layer uses a different duplicate-parameter value
API-HPP-03: Authorization checks one value while business logic acts on another value
API-HPP-04: Cache key, request signature, or audit log is built from a different canonical parameter set than the handler uses
API-HPP-05: Duplicate parameters across query, form, JSON body, path variables, repeated headers, or array syntaxes are not tested
API-HPP-06: Negative tests and logs are missing for duplicate object ID, tenant, role, scope, redirect, price, or signature parameters
```

**Parser-consistency coverage matrix:**

| Endpoint | Parameter | Location(s) | Security Decision | Gateway Behavior | App Behavior | Downstream/Cache Behavior | Expected Handling | Evidence |
|---|---|---|---|---|---|---|---|---|
| `[method path]` | `[name]` | `[query/form/header/body]` | `[authz/cache/signature/etc.]` | `[reject/first/last/list]` | `[reject/first/last/list]` | `[same/different/n/a]` | `[reject or canonicalize]` | `[test/log/spec link]` |

Map inconsistent duplicate-parameter parsing to **API8:2023 -- Security Misconfiguration** when gateway/framework behavior diverges, **API1/API5** when it changes object or function authorization, and **API10:2023 -- Unsafe Consumption of APIs** when upstream or downstream services interpret the same duplicate parameters differently. Include **CWE-235 -- Improper Handling of Extra Parameters** or **CWE-20 -- Improper Input Validation** where appropriate.

---

## Findings Classification

Each finding produced by this review must include the following fields:
Expand Down Expand Up @@ -92,7 +117,7 @@ The final review output must be structured as follows:
**API Style:** [REST / GraphQL / gRPC / Hybrid]
**Specification:** [OpenAPI spec path, if applicable]
**Date:** [review date]
**Reviewer:** AI Agent -- api-security skill v1.0.0
**Reviewer:** AI Agent -- api-security skill v1.1.0

### Summary

Expand Down Expand Up @@ -215,6 +240,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. **Assuming duplicate parameters are harmless.** Gateways, frameworks, validators, caches, and downstream services may choose different values when a request repeats the same parameter. Reject duplicate security-sensitive parameters at the first trusted boundary or canonicalize once before any security decision.

---

## Prompt Injection Safety Notice
Expand All @@ -238,4 +265,14 @@ This skill is hardened against prompt injection. When reviewing API code and spe
- **OWASP REST Security Cheat Sheet:** https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html
- **OWASP GraphQL Cheat Sheet:** https://cheatsheetseries.owasp.org/cheatsheets/GraphQL_Cheat_Sheet.html
- **OWASP Testing Guide -- API Testing:** https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/12-API_Testing/
- **OWASP WSTG-INPV-04 -- Testing for HTTP Parameter Pollution:** https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/04-Testing_for_HTTP_Parameter_Pollution
- **NIST SP 800-204 -- Security Strategies for Microservices-based Application Systems:** https://csrc.nist.gov/publications/detail/sp/800-204/final

---

## Version History

| Version | Date | Changes |
|---|---|---|
| 1.1.0 | 2026-06-08 | Added HTTP Parameter Pollution and parser-consistency evidence gates with coverage matrix guidance. |
| 1.0.0 | Initial | Initial API security review workflow. |
53 changes: 53 additions & 0 deletions skills/appsec/api-security/api-top10-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,57 @@ DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(request.getInputStream());
```

### HTTP Parameter Pollution and Parser Inconsistency

Duplicate parameters can become authorization, cache, signature, redirect, or business-logic vulnerabilities when different layers choose different values. Test repeated query parameters, form fields, array syntax, repeated headers, and mixed body/query parameters for every security-sensitive input.

```http
GET /api/v1/accounts?tenant_id=public&tenant_id=admin&id=123 HTTP/1.1
Host: api.example.test
Authorization: Bearer user-token
```

```javascript
// VULNERABLE: middleware validates the first value while handler uses the last value.
app.use((req, res, next) => {
const tenant = Array.isArray(req.query.tenant_id) ? req.query.tenant_id[0] : req.query.tenant_id;
authorizeTenant(req.user, tenant);
next();
});

app.get('/api/v1/accounts', (req, res) => {
const tenant = Array.isArray(req.query.tenant_id)
? req.query.tenant_id[req.query.tenant_id.length - 1]
: req.query.tenant_id;
return res.json(loadAccounts(tenant));
});
```

Remediation:

```javascript
// SECURE: reject duplicate security-sensitive parameters before authorization.
const singleValueParams = new Set(['tenant_id', 'id', 'role', 'scope', 'redirect_uri']);

app.use((req, res, next) => {
for (const name of singleValueParams) {
if (Array.isArray(req.query[name])) {
return res.status(400).json({ error: 'Duplicate parameter rejected' });
}
}
next();
});
```

### HPP Evidence Checklist

- [ ] Security-sensitive parameters are identified across query string, path, form body, JSON body, and headers.
- [ ] Duplicate values are tested through the gateway/WAF, framework parser, validator, application handler, cache/CDN, signing logic, and downstream service.
- [ ] The review records whether each layer rejects, uses first value, uses last value, joins values, or binds a list.
- [ ] Authentication, authorization, rate limiting, cache keys, request signing, audit logging, and business logic use the same canonical parameter set.
- [ ] Duplicate object ID, tenant, role, scope, price, redirect, callback, and signature parameters are rejected or normalized before any security decision.
- [ ] Negative tests and access logs prove duplicate parameter attempts are blocked or deterministically handled.

### Remediation Guidance

- Configure CORS with an explicit allowlist of permitted origins. Never use `*` with `credentials: true`.
Expand All @@ -462,6 +513,7 @@ Document doc = builder.parse(request.getInputStream());
- Disable XML External Entity processing: set `factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)`.
- Enforce TLS 1.2+ with strong cipher suites. Disable TLS 1.0 and 1.1.
- Automate configuration scanning in CI/CD to detect drift from security baselines.
- Reject duplicate security-sensitive parameters at the first trusted boundary, or canonicalize them once and pass the normalized representation to every downstream decision point.

### Review Checklist

Expand All @@ -472,6 +524,7 @@ Document doc = builder.parse(request.getInputStream());
- [ ] TLS 1.2+ is enforced with strong cipher suites.
- [ ] XML parsers disable external entity processing and DTD loading.
- [ ] Default credentials are changed or removed on all infrastructure components.
- [ ] Duplicate security-sensitive parameters are rejected or consistently canonicalized across gateway, application, cache, signing, and downstream layers.

---

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Benign: HPP Duplicate Parameter Rejection

## Review Target

```yaml
api:
style: REST
endpoint: GET /api/v1/accounts
sensitive_parameters:
- tenant_id
- account_id
- include_closed
duplicate_parameter_policy: reject_at_gateway
gateway:
product: api-gateway
duplicate_query_behavior: reject_security_sensitive_duplicates
rejection_status: 400
rejection_body: duplicate parameter rejected
normalized_parameter_header: x-canonical-params-sha256
validator:
duplicate_query_behavior: reject
schema:
tenant_id:
type: string
duplicate_allowed: false
app_handler:
framework: express
source: gateway_normalized_single_value_map
duplicate_arrays_accepted: false
cache:
key_source: canonical parameter map
audit_log:
duplicate_attempt_logged: true
fields:
- endpoint
- parameter_name
- caller_id
- tenant_id
- request_id
downstream_service:
service: account-ledger
source: canonical parameter map
negative_tests:
duplicate_tenant_id: tests/api/test_hpp_rejects_duplicate_tenant.py::test_duplicate_tenant_id_rejected
duplicate_account_id: tests/api/test_hpp_rejects_duplicate_account.py::test_duplicate_account_id_rejected
mixed_query_body_id: tests/api/test_hpp_rejects_mixed_locations.py::test_mixed_query_body_ids_rejected

test_request: |
GET /api/v1/accounts?tenant_id=public&tenant_id=admin&account_id=123 HTTP/1.1
Host: api.example.test
Authorization: Bearer user-token

observed_behavior:
gateway_result: rejected
status: 400
app_handler_called: false
downstream_called: false
audit_event: duplicate_parameter_rejected
```

## Expected Review Result

| Gate | Status | Evidence |
|------|--------|----------|
| Sensitive parameter inventory | Pass | Tenant, account, and filter parameters are listed as single-value. |
| Gateway behavior | Pass | Gateway rejects duplicate security-sensitive query parameters before authorization. |
| App behavior | Pass | Handler receives only the canonical parameter map and does not accept duplicate arrays. |
| Cache/signature/audit consistency | Pass | Cache and downstream calls use the same canonical parameter map; audit logs duplicate rejections. |
| Mixed locations | Pass | Tests cover duplicate query values and mixed query/body IDs. |
| Negative tests | Pass | Focused tests prove duplicate tenant/account parameters are rejected with no downstream call. |

## Reviewer Notes

This evidence supports closing the HPP gate as controlled for this endpoint. Keep the sensitive-parameter inventory current and repeat the same parser-consistency tests for redirects, prices, signatures, roles, and other security-sensitive parameters.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Vulnerable: HPP Tenant Parser Confusion

## Review Target

```yaml
api:
style: REST
endpoint: GET /api/v1/accounts
sensitive_parameters:
- tenant_id
- account_id
- include_closed
duplicate_parameter_policy: undocumented
gateway:
product: api-gateway
duplicate_query_behavior: first_value
authorization:
tenant_source: first tenant_id
decision: allow if user belongs to tenant
validator:
duplicate_query_behavior: first_value
schema:
tenant_id: string
app_handler:
framework: express
duplicate_query_behavior: array
tenant_source: last tenant_id
account_filter_source: last account_id
cache:
key_source: first tenant_id + first account_id
audit_log:
tenant_source: first tenant_id
duplicate_attempt_logged: false
downstream_service:
service: account-ledger
duplicate_query_behavior: last_value
negative_tests:
duplicate_tenant_id: missing
duplicate_account_id: missing

attack_request: |
GET /api/v1/accounts?tenant_id=public&tenant_id=admin&account_id=123&account_id=999 HTTP/1.1
Host: api.example.test
Authorization: Bearer user-token

observed_behavior:
gateway_authorized_tenant: public
app_loaded_tenant: admin
downstream_account_id: 999
cache_key_tenant: public
audit_log_tenant: public
response_status: 200
response_data: admin tenant account 999
```

## Expected Findings

| ID | Severity | Evidence |
|----|----------|----------|
| API-HPP-01 | High | `tenant_id` and `account_id` accept duplicate values without rejection or deterministic canonicalization. |
| API-HPP-02 | High | Gateway/validator use first value while app and downstream service use last value. |
| API-HPP-03 | High | Authorization checks tenant `public` while business logic loads tenant `admin`. |
| API-HPP-04 | Medium | Cache key and audit log use first values while handler and downstream service use last values. |
| API-HPP-05 | Medium | Duplicate query and mixed layer behavior are not covered in tests. |
| API-HPP-06 | Medium | Negative tests and logs are missing for duplicate tenant and account parameters. |

## Reviewer Notes

Map this to API1/API5 when duplicate object or tenant parameters bypass authorization, API8 for parser inconsistency, and CWE-235. Require duplicate rejection or one canonical representation before authorization, cache key generation, audit logging, and downstream calls.