GraphQL Security: Automated Security Testing of GraphQL Backed Applications

Adam Baldwin
Adam Baldwin
Share on twitter
Share on facebook
Share on linkedin
Share on reddit
Adam Baldwin

Adam Baldwin

Share on twitter
Share on facebook
Share on linkedin
Share on reddit

Working with the latest tech is fun. It’s fresh and exciting. As developers we feel invigorated by being on the bleeding edge. Consider us thrill seekers.

Thrills, however, shouldn’t come from 2am alerts resulting in the binge triaging of production security bugs found in that latest tech stack. Perhaps it’s the reason you’re here. Perhaps you believe, like we do, that bugs are best squashed before deploying to prod. 

StackHawk was built to help developers ship secure applications. Existing security testing tools do not work well with modern development paradigms. We’ve built functionality to ensure that modern developers can run security tests simply, including CI integrations, scanning REST API backed applications, and more. 

As we work to cover the modern application stack, we were well aware of the black hole for GraphQL security testing. We just released GraphQL scanning support to ensure that you can ship secure GraphQL APIs.

But before we jump into the specifics of the solution and follow up with a demo, let’s do a quick overview of the GraphQL specification. This is a unique space with an interesting set of challenges. 

If you’re already well versed in GraphQL and the potential challenges posed by its current state of scan-ability, please feel free to skip ahead to How it Works for a demo and walkthrough. 

If you enjoy a little flavor and some additional back story then I welcome you to join me on a brief detour.

Do you even Graph(QL)?

Now unless your tech stack has been in a quarantine with the rest of us, you’ve probably seen GraphQL implementations in the wild. If your business is inline with, or already one of the 3,026 star adopters reported in the GraphQL Landscape, then you’re probably already building and deploying a GraphQL API in production today. 

Again, being at the forefront of change is always an exciting adventure, but have you taken time to ask yourself…

How secure is my GraphQL API?

If we take a look at some of the numbers, such as the GraphQL statistics report for Drupal customers or this survey on the most exciting API technologies, we get a sense of how this new specification continues gaining traction. 

A rising popularity of any new technology typically results in a rise in broken implementations. Considering most of these apps are likely to lack proper testing we suddenly have some serious concerns.

While our craft remains the same despite new paradigms, the way in which we express ourselves through our systems will naturally have to be adjusted. This change presents a potential breeding ground for unchecked vulnerabilities on new and existing web apps. 

At StackHawk, we believe it is important to simplify and automate security testing for your applications.

So… it’s like, graphs and stuff, right?

Indeed. The specification on the surface defines an outline for representing and interfacing with your data… as a graph and stuff.

At its core GraphQL works on the principle that data is interconnected and can be effectively represented as vertices on a graph. Most of us will be aware that this means two or more pairs of connected vertices, having one or more edges which may or may not come together to form forests, trees and leaves in a directed, acyclical or cyclical fashion, etc, ad infinitum recursively, and on and on.

This is all just to say that the designers of GraphQL have brilliantly outlined the capacity for engineers to represent data in pretty much any complex structure desired (or maybe not desired). Anything goes as long as the implementation is within the confines of the specification and meets a few key criteria. 

It’s the Wild West of the web!  In fact, if you live in a quiet part of the city on dark summer evenings and draw the blinds, turn down the lights, and listen very carefully, you may just catch the sound of the faint grumblings emitted by backend engineers all over as they beg for mercy from the agony of rearchitecting their RESTful service into the promised land The Graph.

Now, this is dangerously close to falling into some wretched and poorly written essay about graph theory and the GraphQL API, but that would never be nearly as informative as what’s already available at GraphQL so let’s fast forward to what this all means for the security bottom-line. 

Interest in Introspection

One key feature of GraphQL that we at StackHawk, and your potential attacker no doubt, will employ in our endeavors to discover and audit routes is one of introspection.

An introspection query allows a client to request a fully inclusive description of the API in a single query, which can contain all the definitions of types, fields, custom types, primitives, directives, subscriptions and other operations which we can query. 

HawkScan gathers this introspection data and quickly begins to determine available routes throughout the app. It then proceeds to generate queries which include fields and dependencies, expected input values, and available parameters to use as variable arguments. We provide the required input types, unwrapped custom types, scalars, enums, lists and so on and insert test values wherever possible. 

Along with this automatic discovery and generation of both query and mutation requests, we further provide the ability to tune the scanner with options such as making GET vs POST requests, setting recursion depth on introspection, and setting control over the method of how queries are generated. The latter being configurable for either batch form compost of all fields and types, or individual requests with each field and required type sent one-by-one.

The Faces May Change, but Security Bugs Remain the Same

SQL Injection is SQL Injection whether the route exists in a REST endpoint, an input form with sanitization missing, or a field query that takes an input parameter in GraphQL. Remote code injections are possible here, as they have been from the beginning of web applications, and they aren’t going away any time soon. 

Security through obscurity is not a viable practice. If you have GraphQL running in your ecosystem, we’ll help you ensure that you ship secure applications.

Let’s see it in action!

How it Works: Walk through with a Sample App

Adding security testing to your GraphQL application is easy with StackHawk. We used the very nice Vulnerable GraphQL project from our friends at Carve Systems to spin up an application to test with. Below are details of how to test it with our sample vulnerable GraphQL application. This will also serve as an example of how you can set up StackHawk to scan your own app.

We begin by pulling down StackHawk’s vulnerable GraphQL project from Github.

git clone https://github.com/stackhawk/vuln-graphql-api.git

Choose a listening port for the app and build the project with docker-compose:

SERVER_PORT=3000 docker-compose up
Starting a test GraphQL application for security testing.

Once done, you’ll have a vulnerable GraphQL instance to attack. Now, let’s run the HawkScan, StackHawk’s security scanner.

Log in to your StackHawk Account (or sign up if you don’t have an account) and create a new application.

Signing into StackHawk.
The user interface in StackHawk for adding a new application to test for security bugs.

Make sure to provide the http://localhost and the selected port that reflects your setup:

Creating a new application in StackHawk's app to run security tests.

If you’ve run through StackHawk’s initial setup during account creation, you should already have a hawk.rc file saved in an accessible location. This contains the HAWK_API_KEY that links to your account. If this is missing, simply generate a new key in the Account UI and populate that file.

After creating the new application, download the generated stackhawk.yml base file and place it in the source’s path. Then, go ahead and edit with your favorite editor (I’m not biased but VIM).

Inside we’ll add two new lines under the app portion of the yaml:

app:
  # .... other config parameters
  graphqlConf:
    enabled: true
    schemaPath: '/graphql'
    operation: ALL
    batchQueries: true

With that, we’re ready to scan. Initiate the scan with the following:

source ~/.hawk/hawk.rc
docker run -e API_KEY=${HAWK_API_KEY} --rm -v $(pwd):/hawk:rw -it stackhawk/hawkscan:latest
Command line output as StackHawk pulls down the latest Docker container for GraphQL security testing.

HawkScan updates the status and progress on the terminal while it runs. GraphQL focused scans will typically find a lot more routes, so expect some longer runtimes.

Command line output as StackHawk begins to run a GraphQL security test.
Terminal output from a GraphQL Security Scan from StackHawk

Upon completion you’ll see the output of all discovered routes and alerts. We can see in the output of our scan that we’ve found two high severity bugs in this vulnerable GraphQL app. One for SQL Injection and another for Remote Code Execution. 

These are two nasty bugs that you hopefully will never see in your app. If you have StackHawk running tests on every PR, then you know these bugs will never see the light of prod. 

Back in the UI, our results are now available under the Applications view:

Findings of a GraphQL Security Testing Scan in the StackHawk application.

Browse the findings and we can now grab the original request query and response and proceed to take action, accordingly.

Let’s have a quick look at the Remote OS Command Injection alert. 

We find our GraphQL query present in the Request view:

{"query":"mutation superSecretPrivateMutation($command:String ) { superSecretPrivateMutation(command:$command) { stdout stderr } }","variables":{"command":"KaaaKaww!&cat /etc/passwd&"}}

And the response in the Response view:

{"data":{"superSecretPrivateMutation":{"stdout":"
root:x:0:0
:root:/root:/bin/bash\nbin:x:1:1:bin:/bin:/sbin/n
root:x:0:0
:root:/root:/bin/bash\nbin:x:1:1:bin:/bin:/sbin/nologin\ndaemon:x:2:2:daemon:/sbin:/sbin/nologin\nadm:x:3:4:adm:/var/adm:/sbin/nologin\nlp:x:4:7:lp:/var/spool/lpd:/sbin/nologin\nsync:x:5:0:sync:/sbin:/bin/sync\nshutdown:x:6:0:shutdown:/sbin:/sbin/shutdown\nhalt:x:7:0:halt:/sbin:/sbin/halt\nmail:x:8:12:mail:/var/spool/mail:/sbin/nologin\noperator:x:11:0:operator:/root:/sbin/nologin\ngames:x:12:100:games:/usr/games:/sbin/nologin\nftp:x:14:50:FTP User:/var/ftp:/sbin/nologin\nnobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin\ndbus:x:81:81:System message bus:/:/sbin/nologin\nsystemd-coredump:x:999:997:systemd Core Dumper:/:/sbin/nologin\nsystemd-resolve:x:193:193:systemd Resolver:/:/sbin/nologin\napp:x:1000:1000::/home/app:/bin/bash\n","stderr":"/bin/sh: KaaaKaww!: command not found\n"}}}

This would be a frightening sight, indeed, if this had been a production bug!

That concludes this week’s HawkTastic adventure, folks. And remember, make sure to always run StackHawk to help keep your web services fortified, healthy, happy, and most importantly, free of security bugs. Until next time, be sure to scan early and scan often!

KAAKAWW!

More StackHawk
Ryan Severns
Zachary Conger
Scott Gerlach

KAAKAWW!!! [ kǝn'grats ]

The Demo Gods Approve!
We’ll reach out to you soon to schedule a 45 minute demo. Please complete this 3 minute survey so we can prepare a demo that is specific to you.

KAAKAWW!!! [ kǝn'grats ]

You're signed up for the newsletter!
We’ll keep you up to date on content and other happenings here at StackHawk.