Skip to content

[HIGH] Directive Overloading - Multiple duplicated directives allowed in a query (Denial of Service - /graphql) #1673

Open
@vadimbalakhanov

Description

@vadimbalakhanov

Hi guys we are facing pen testing now. We got some vulnerabilities and almost all of them were solved by using in-built validators but one of them is still present

[HIGH] Directive Overloading - Multiple duplicated directives allowed in a query (Denial of Service - /graphql)

Script example how to break the system:
curl --path-as-is -i -s -k -X $'POST'
-H $'Host: api-acc.expoze.app'
-H $'User-Agent: graphql-cop/1.13'
-H $'Accept-Encoding: gzip, deflate, br'
-H $'Accept: /'
-H $'Content-Length: 98612'
-H $'Content-Type: application/json'
-o /dev/null
-w "Time elapsed: %{time_total} seconds\nResponse size: %{size_download} bytes\n"
--data-binary $'{"query": "query cop { __typename @aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@aa@[email protected]}", "operationName": "cop"}'
$'https://api-acc.expoze.app/graphql'

I tried to use custom validator
`<?php

namespace App\GraphQL\Rule;

use GraphQL\Error\Error;
use GraphQL\Language\AST\DirectiveNode;
use GraphQL\Language\AST\OperationDefinitionNode;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Validator\QueryValidationContext;
use GraphQL\Validator\Rules\ValidationRule;
use GraphQL\Validator\SDLValidationContext;

class LimitDirectivesAndAliases extends ValidationRule
{
// Set your desired directive limit
private const MAX_DIRECTIVES = 10;

public function getSDLVisitor(SDLValidationContext $context): array
{
    return [
        NodeKind::OPERATION_DEFINITION => [
            'leave' => function (OperationDefinitionNode $operation) use ($context): void {
                $seenDirectives = [];

                foreach ($operation->directives as $directive) {
                    $directiveName = $directive->name->value;

                    // Count the occurrences of each directive
                    if (!isset($seenDirectives[$directiveName])) {
                        $seenDirectives[$directiveName] = 0;
                    }
                    $seenDirectives[$directiveName]++;

                    // Report an error if the directive exceeds the max allowed
                    if ($seenDirectives[$directiveName] > self::MAX_DIRECTIVES) {
                        $context->reportError(
                            new Error(
                                sprintf(
                                    'The directive "@%s" may be used only %d times per operation.',
                                    $directiveName,
                                    self::MAX_DIRECTIVES
                                ),
                                [$directive]
                            )
                        );
                    }
                }
            }
        ]
    ];
}

}
`

getVisitor(QueryValidationContext $context) - also is not working

but problem is still there. I am lost a bit. May be it is known issue and you have some built in solutions how to solve it. Or probably I misunderstood smth. I really hope you can help me here coz clients wait and I am crying :) Thank you in advance :)

This is rules used:
` // Configure Query Complexity
$maxQueryComplexity = 100; // Set your desired complexity limit
DocumentValidator::addRule(new QueryComplexity($maxQueryComplexity));

    // Configure Query Depth
    $maxDepth = 10; // Set your desired depth limit
    DocumentValidator::addRule(new QueryDepth($maxDepth));
    // Disable Introspection
    DocumentValidator::addRule(new DisableIntrospection(DisableIntrospection::ENABLED));
    DocumentValidator::addRule(new UniqueDirectivesPerLocation());
    DocumentValidator::addRule(new UniqueDirectiveNames());
    DocumentValidator::addRule(new LimitDirectivesAndAliases());`

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions