Configuration¶
GraphQLer reads a TOML file passed with --config. Without it, <PATH>/config.toml is used if present, otherwise one is generated there. CLI flags override the file, and the resolved configuration is written back to <PATH>/config.toml on every run.
Common settings¶
| Variable | Description | Type | Default |
|---|---|---|---|
MAX_LEVENSHTEIN_THRESHOLD |
Levenshtein distance for matching object names to ID inputs | Integer | 20 |
MAX_OBJECT_CYCLES |
Max times the same object is materialised in one query/mutation | Integer | 5 |
MAX_OUTPUT_SELECTOR_DEPTH |
Max depth of output selections (guards against recursive types) | Integer | 5 |
USE_OBJECTS_BUCKET |
Store returned objects for later requests | Boolean | true |
USE_DEPENDENCY_GRAPH |
Order requests using the dependency graph | Boolean | true |
ALLOW_DELETION_OF_OBJECTS |
Remove objects from the bucket after a successful DELETE | Boolean | false |
MAX_FUZZING_ITERATIONS |
Number of sweeps through all chains | Integer | 1 |
MAX_TIME |
Maximum run time in seconds | Integer | 3600 |
REQUEST_TIMEOUT |
Per-request timeout in seconds | Integer | 120 |
TIME_BETWEEN_REQUESTS |
Minimum delay between requests in seconds | Float | 0.001 |
DEBUG |
Debug mode | Boolean | false |
SKIP_MAXIMAL_PAYLOADS |
Skip payloads that request every possible output field | Boolean | false |
SKIP_DOS_ATTACKS |
Skip DoS detections (on by default to avoid taking the service down) | Boolean | true |
SKIP_INJECTION_ATTACKS |
Skip injection detections | Boolean | false |
SKIP_MISC_ATTACKS |
Skip miscellaneous detections | Boolean | false |
SKIP_ENUMERATION_ATTACKS |
Skip field-charset and ID enumeration detections (many requests per node) | Boolean | true |
SKIP_SUBSCRIPTIONS |
Skip subscription fuzzing (--subscriptions enables it) |
Boolean | true |
SUBSCRIPTION_PROTOCOL |
graphql-transport-ws or legacy subscriptions-transport-ws |
String | graphql-transport-ws |
SKIP_NODES |
Query/mutation names to skip | List | [] |
DISABLE_MUTATIONS |
Only generate and run Query chains (--disable-mutations) |
Boolean | false |
SAVE_ENDPOINT_RESULTS |
Write per-endpoint result files | Boolean | true |
IDOR_SECONDARY_AUTH |
Secondary (attacker) token for IDOR chains | String | unset |
SKIP_IDOR_CHAIN_FUZZING |
Disable the IDOR chain phase | Boolean | false |
SKIP_UAF_CHAIN_FUZZING |
Disable the use-after-delete chain phase | Boolean | false |
[CUSTOM_HEADERS] |
Headers sent with every request | Table | Accept = "application/json" |
LLM settings are described in LLM features.
Custom headers¶
Authentication profiles¶
--auth sets the primary Authorization header. Named profiles are passed as profile=token:
python -m graphqler --mode run --url <URL> \
--auth 'primary=Bearer <VICTIM_TOKEN>' \
--auth 'secondary=Bearer <ATTACKER_TOKEN>'
primary is the default identity; secondary is equivalent to --idor-auth and enables IDOR chains.
Example configuration¶
An annotated example shipped with GraphQLer (graphqler/examples/config.toml). Defaults in the table above come from graphqler/config.py.
# Configuration
# For debugging purposes
DEBUG = false
# For clairvoyance
WORDLIST_PATH = "static/wordlist.txt"
# For the resolver
MAX_LEVENSHTEIN_THRESHOLD = 20 # A very high threshold, we could probably lower this, but this almost guarantees us to find a matching object name - ID
# ── LLM-based dependency resolver (opt-in) ────────────────────────────────────
# When enabled, GraphQLer sends the full schema to an LLM and asks it to infer
# dependency relationships (hardDependsOn / softDependsOn / mutationType).
# This catches cases the classic ID-name-matching resolver misses:
# - String inputs that semantically reference an object (e.g. userEmail → User)
# - Unconventional mutation verb names (provision, wipe, spawn → CREATE/DELETE)
# - Non-English or domain-specific naming
#
# Model string uses litellm format (provider/model):
# OpenAI: "gpt-4o-mini" + LLM_API_KEY or OPENAI_API_KEY env var
# Anthropic: "anthropic/claude-3-5-haiku-20241022" + LLM_API_KEY or ANTHROPIC_API_KEY env var
# Ollama (local): "ollama/llama3" + LLM_BASE_URL = "http://localhost:11434"
# LiteLLM proxy: "openai/my-model" + LLM_BASE_URL = "http://my-proxy:4000"
# ──────────────────────────────────────────────────────────────────────────────
USE_LLM = false # master toggle
LLM_USE_FOR_COMPILATION = true # when USE_LLM=true, apply LLM in compilation phase (dependency resolver, IDOR/UAF chain classifiers)
LLM_USE_FOR_FUZZING = true # when USE_LLM=true, apply LLM in fuzzing phase (payload generation, error retry, endpoint classification, reporting)
LLM_MODEL = "gpt-4o-mini" # litellm model string
LLM_API_KEY = "" # API key; if empty, reads from env (OPENAI_API_KEY, etc.)
LLM_BASE_URL = "" # custom base URL (required for Ollama / LiteLLM proxies)
LLM_RESOLVER_FALLBACK_TO_ID = true # fall back to classic resolver if LLM call fails
LLM_RESOLVER_SAVE_COMPARISON = true # save eval/resolver_comparison.json (LLM vs classic diff)
LLM_MAX_RETRIES = 2 # retry attempts when LLM returns non-JSON (0 = no retries)
# For the linker
GRAPH_VISUALIZATION_OUTPUT = "dependency_graph.png"
# For materializers
MAX_OBJECT_CYCLES = 3
MAX_OUTPUT_SELECTOR_DEPTH = 3
HARD_CUTOFF_DEPTH = 20
MAX_INPUT_DEPTH = 20
# For using GraphQLer in different modes
USE_OBJECTS_BUCKET = true # Ablation: set false to disable state tracking (objects bucket)
USE_DEPENDENCY_GRAPH = true # Ablation: set false to run all nodes without chain ordering
NO_DATA_COUNT_AS_SUCCESS = false # Count empty data responses as successes
DISABLE_MUTATIONS = false # When true, only Query chains are generated — all Mutation nodes are excluded from fuzzing
# For fuzzing
ALLOW_DELETION_OF_OBJECTS = false # Remove deleted objects from bucket after a successful DELETE mutation
MAX_FUZZING_ITERATIONS = 1 # Number of times to iterate through all chains (increase for more coverage)
MAX_TIME = 3600 # in seconds
SKIP_MAXIMAL_PAYLOADS = false # This mode is for when we want to skip the maximal payloads
SKIP_DOS_ATTACKS = true # This mode is for when we want to skip the DoS check
SKIP_INJECTION_ATTACKS = false # This mode is for when we want to skip the injection check
SKIP_MISC_ATTACKS = false # This mode is for when we want to skip the miscellaneous attacks
SKIP_SUBSCRIPTIONS = true # Disable subscription fuzzing by default (requires WebSocket support); enable with --subscriptions
SUBSCRIPTION_TIMEOUT = 1 # Seconds to wait for events on each subscription
SUBSCRIPTION_PROTOCOL = "graphql-transport-ws" # "graphql-transport-ws" (modern) or "subscriptions-transport-ws" (legacy Apollo)
# For stats output
SAVE_ENDPOINT_RESULTS = true # Set false to skip writing per-endpoint result files (can be large)
# For each request
REQUEST_TIMEOUT = 120 # in seconds
TIME_BETWEEN_REQUESTS = 0.001 # in seconds
# ── Chain-based IDOR detection (cross-user access testing) ───────────────────
# When IDOR_SECONDARY_AUTH is set, the compiler generates IDOR candidate chains
# during compilation and saves them to chains.yml. The fuzzer then runs the
# setup nodes with the primary token (victim) so that resources are created,
# and the test nodes with the secondary token (attacker) to check for IDOR.
#
# Usage:
# Set IDOR_SECONDARY_AUTH to the attacker's Bearer token, OR pass it via the
# --idor-auth CLI flag (which takes precedence).
#
# Heuristic scoring signals (0.0–1.0):
# +0.5 CREATE mutation output type matches the test node's input type
# +0.3 test node name contains private-resource keywords (user/order/profile…)
# +0.2 test node accepts an ID/Int parameter
# -0.2 test node name contains public-resource keywords (list/public/catalog…)
#
# Chains scoring below IDOR_HEURISTIC_CONFIDENCE_THRESHOLD are sent to the LLM
# classifier when IDOR_USE_LLM_FALLBACK = true (requires USE_LLM = true).
# ──────────────────────────────────────────────────────────────────────────────
IDOR_SECONDARY_AUTH = "" # Attacker/secondary Bearer token; empty = IDOR phase skipped
SKIP_IDOR_CHAIN_FUZZING = false # Set true to disable the IDOR phase even when a secondary token is configured
IDOR_HEURISTIC_CONFIDENCE_THRESHOLD = 0.5 # Chains below this score trigger LLM fallback (when enabled)
IDOR_USE_LLM_FALLBACK = false # Use LLM classifier for low-confidence chains (requires USE_LLM = true)
# For custom skipping specific nodes"""
SKIP_NODES = []
# Put custom headers here
[CUSTOM_HEADERS]
Accept = "application/json"