-
Notifications
You must be signed in to change notification settings - Fork 2
Template System
Hadrian security tests are defined using YAML templates — declarative files that specify which endpoints to test, which role combinations to use, and how to detect vulnerabilities. You can use the 30 built-in templates or write custom ones for application-specific authorization rules.
| Type | Pattern | Use Case | Phases |
|---|---|---|---|
| Simple | test_pattern: "simple" |
Read operations, BFLA checks, data exposure | Single request |
| Mutation | test_pattern: "mutation" |
Write/delete operations that modify state | Setup → Attack → Verify |
Every template has four sections:
id: api1-bola-cross-user
info:
name: "BOLA - Cross-User Resource Access"
category: "API1:2023"
severity: "HIGH"
description: |
Tests for Broken Object Level Authorization by attempting
to access resources belonging to other users.
tags: ["bola", "owasp-api-top10", "api1"]
requires_llm_triage: true
test_pattern: "simple"| Field | Required | Description |
|---|---|---|
id |
Yes | Unique template identifier |
name |
Yes | Human-readable test name |
category |
Yes | OWASP category (e.g., "API1:2023") |
severity |
Yes | CRITICAL, HIGH, MEDIUM, LOW |
description |
No | Detailed explanation |
tags |
No | Categorization tags |
requires_llm_triage |
No | Enable AI analysis of findings |
test_pattern |
Yes | "simple" or "mutation" |
Filters which endpoints this template applies to:
endpoint_selector:
has_path_parameter: true # Only test endpoints with {id} parameters
requires_auth: true # Only authenticated endpoints
methods: ["GET", "PUT"] # HTTP methods to matchFor gRPC:
endpoint_selector:
requires_auth: true
methods: ["Get*", "Read*", "Fetch*"] # gRPC method name patternsDefines attacker/victim role combinations:
role_selector:
attacker_permission_level: "lower" # Less privileged attacker
victim_permission_level: "higher" # More privileged victim| Value | Meaning |
|---|---|
"lower" |
Roles with lower level than the counterpart |
"higher" |
Roles with higher level than the counterpart |
"all" |
All roles |
"none" |
Unauthenticated access (no auth header sent) |
How to identify vulnerabilities:
detection:
success_indicators:
- type: status_code
status_code: 200
- type: body_contains
pattern: "\"id\":"
failure_indicators:
- type: status_code
status_code: 403
- type: status_code
status_code: 401Vulnerability found if: Response matches ALL success_indicators and NONE of the failure_indicators.
| Type | Fields | Description |
|---|---|---|
status_code |
status_code |
HTTP status code match |
body_contains |
pattern |
Response body contains string |
body_field |
body_field, exists
|
JSON field exists in response |
grpc_status |
code |
gRPC status code (single or array) |
id: api1-bola-read
info:
name: "BOLA - Cross-User Resource Read"
category: "API1:2023"
severity: "HIGH"
test_pattern: "simple"
endpoint_selector:
has_path_parameter: true
requires_auth: true
methods: ["GET"]
role_selector:
attacker_permission_level: "lower"
victim_permission_level: "higher"
http:
- method: "{{method}}"
path: "{{path}}"
headers:
Authorization: "{{attacker_auth}}"
detection:
success_indicators:
- type: status_code
status_code: 200
- type: body_contains
pattern: "\"id\":"
failure_indicators:
- type: status_code
status_code: 403id: api1-bola-delete
info:
name: "BOLA - Unauthorized Resource Deletion"
category: "API1:2023"
severity: "CRITICAL"
test_pattern: "mutation"
endpoint_selector:
has_path_parameter: true
requires_auth: true
methods: ["DELETE"]
role_selector:
attacker_permission_level: "lower"
victim_permission_level: "higher"
test_phases:
setup:
- path: "/api/user/dashboard"
auth: "victim"
store_response_fields:
victim_id: "id"
victim_video_id: "video_id"
attack:
path: "/api/resource/{victim_video_id}"
auth: "attacker"
operation: "delete"
expected_status: 200
verify:
path: "/api/resource/{victim_video_id}"
auth: "victim"
check_field: "status"
expected_value: "deleted"
detection:
success_indicators:
- type: status_code
status_code: 200
failure_indicators:
- type: status_code
status_code: 403
conditions:
- attack_phase_status: [200]
verify_phase_status: [404]| Field | Phase | Description |
|---|---|---|
path |
All | Endpoint to call |
auth |
All | Role credentials to use ("victim" or "attacker") |
operation |
Attack | "create", "update", "delete", "read" |
data |
Setup | Request body fields |
store_response_field |
Setup | JSON path to extract from response |
store_response_fields |
Setup | Map of field names to JSON paths |
use_stored_field |
Attack/Verify | Use previously stored field |
expected_status |
All | Expected status code |
check_field |
Verify | Field to check for changes |
expected_value |
Verify | Expected field value after attack |
store_response_fields uses JSON path expressions supporting dot-separated object key traversal only (e.g., data.user.id). Array indexing, keys containing dots, and nested arrays are not supported.
id: graphql-bola
info:
name: "GraphQL BOLA"
category: "API1:2023"
severity: "HIGH"
test_pattern: "simple"
endpoint_selector:
requires_auth: true
role_selector:
attacker_permission_level: "lower"
victim_permission_level: "higher"
graphql:
- query: |
query { user(id: "{{victim_id}}") { email ssn } }
auth: "attacker"
detection:
success_indicators:
- type: status_code
status_code: 200
- type: body_field
body_field: "data.user"
exists: trueid: grpc-bola-read
info:
name: "gRPC BOLA Read"
category: "API1:2023"
severity: "HIGH"
test_pattern: "simple"
endpoint_selector:
requires_auth: true
methods: ["Get*", "Read*"]
role_selector:
attacker_permission_level: "lower"
victim_permission_level: "higher"
grpc:
- method: "{{operation.method}}"
service: "{{operation.service}}"
message: '{"{{operation.owner_field}}": "{{victim_id}}"}'
metadata:
authorization: "Bearer {{attacker_token}}"
detection:
success_indicators:
- type: "grpc_status"
code: 0
failure_indicators:
- type: "grpc_status"
code: [7, 16]Templates are loaded and executed in alphabetical order by filename. Prefix filenames with numbers to control order:
-
01-*to05-*: Non-destructive read tests -
06-*to07-*: Write/modification tests -
08-*to09-*: Destructive delete tests
This ensures read tests run before tests that modify or delete data.
| Variable | Description |
|---|---|
{{method}} |
HTTP method (GET, POST, etc.) |
{{path}} |
Endpoint path |
{{attacker_auth}} |
Attacker's auth header value |
{{victim_id}} |
Victim's user/resource ID |
{{attacker_id}} |
Attacker's user/resource ID |
{{attacker_token}} |
Attacker's raw token |
{{random_id}} |
Random string for unique resources |
{{operation.method}} |
gRPC method name |
{{operation.service}} |
gRPC service name |
{{operation.owner_field}} |
Field that identifies resource owner |
{{operation.resource_type}} |
Resource type name |