Built-in ID scalar used in input instead of a custom scalar
Issue ID: graphql-data-input-custom-scalar-id-needed
Average severity: Critical
Description
The schema uses a built-in scalar of the type ID in an input position (argument or input object field) instead of using a domain-specific custom scalar.
For more details, see the GraphQL specification.
Possible exploit scenario
In GraphQL, the built-in ID scalar is defined as a unique identifier serialized as a string. However, this poses several problems:
- It accepts any string or integer value
- It has no format or length constraints
- It carries no semantic meaning
- It does not express ownership, tenant scope, or domain boundaries
- It does not enforce structural validation
In practice, identifiers in GraphQL APIs are frequently used to:
- Reference business entities (
userId,accountId,orderId) - Control ownership (
tenantId,organizationId) - Modify or delete objects
- Establish relationships between entities
Because identifiers are often directly tied to authorization decisions, using an unconstrained built-in ID in input position increases the risk of:
- Broken Object Level Authorization (BOLA)
- Cross-tenant access
- Insecure direct object reference patterns
- Type confusion between identifiers belonging to different domains
For example, if both UserId and AccountId are defined as ID, the schema does not prevent accidentally passing a valid account identifier where a user identifier is expected. The backend must rely entirely on runtime checks, increasing the risk of implementation errors.
A custom scalar makes the domain semantics explicit and allows enforcing:
- Strict format (UUID, ULID, base64-encoded opaque ID)
- Length constraints
- Namespace or prefix rules
- Structural validation before resolver execution
This improves both security posture and contract clarity.
Remediation
Replace the built-in ID scalar with a domain-specific custom scalar that carries explicit constraints. We recommend that you:
- Define a distinct scalar for each identifier domain, such as:
UserIdAccountIdOrderIdTenantId
- Enforce strict format and length constraints
- Avoid reusing the generic
IDfor security-sensitive references
This reduces ambiguity, strengthens validation at the API boundary, and supports more accurate security auditing and authorization testing.