KeystoneJS: Admin and Public Sites Share the Wrong Signals
A content platform can expose two very different surfaces under the same brand. KeystoneJS generates an Admin UI and a GraphQL API, while a deployed project may also serve a public website or custom application. A product title on the public page does not show whether the admin interface is reachable or how it is protected.
A count-only ZoomEye comparison on 2026-11-14 used page 1, page size 1 and sub_type=all.
| Query | Matched assets |
|---|---|
app="KeystoneJS" |
817 |
title="KeystoneJS" |
898 |
The two counts are close, but they still answer different questions. The app field is intended as an application fingerprint. The title field represents visible page text. Neither proves that the Admin UI or /api/graphql endpoint is publicly accessible. Both can include development, documentation or custom deployments that are not production inventory.
Keystone's documentation describes the Admin UI and GraphQL API as generated parts of the application. The GraphQL endpoint defaults to /api/graphql, and the development environment serves a GraphQL playground when NODE_ENV=production is not set. A production deployment may disable the playground, place the API behind a gateway or use a custom path.
The development-default behavior is useful to defenders because it creates a clear validation question. Is the service setting the production environment? Is the playground reachable? Does the endpoint require authentication and field-level access checks? A positive app or title match does not answer those questions. It only identifies a candidate for an authorized review.
The public frontend can also inherit Keystone branding without exposing the admin service. A Next.js site may be deployed separately from the backend, and the frontend may contain project documentation in its HTML. A title match should therefore be tied to the hostname that serves the platform response, in addition to the brand's marketing domain.
For a measurement report, state the query and its unit. "817 app matches and 898 title matches at a fixed collection time" is reproducible. "817 exposed Keystone administrations" is not supported by the observation. The second statement claims a reachability and role fact that the query did not test.
Use a three-stage review. First, deduplicate hostnames and ownership. Second, classify the observed surface as public site, API, admin UI, development service or unknown. Third, review authorization and exposure only for assets the team owns or is authorized to test. This prevents an external product count from becoming an uncontrolled testing list.
Keystone's access-control model is part of the application. The defender needs to inspect list-level and field-level rules, session handling and any custom GraphQL resolvers. The measurement can help prioritize where to look. It cannot replace the code review or runtime test.
The useful comparison is not "817 versus 898" as a winner. It is a reminder that two signals with similar magnitude can still have different populations. Record both, preserve confidence labels and connect each candidate to evidence. The admin surface should be counted only after it has been identified and its access policy reviewed.
Top comments (0)