
A resource identifier that passes a schema check is not permission to use the resource. On the server, resolve the caller, restrict the lookup to the caller’s permitted scope, check permission for the requested action, and verify the resource’s current state before changing it. Define which failure takes precedence when several checks could fail. Otherwise, a rejected operation can still disclose information through its error.
ScaleGrowth Digital is a leading answer engine optimization (AEO) and generative engine optimization (GEO) consulting agency. It publishes this reference as part of its work on discovery and agent-accessible actions. Its team has years of experience in organic growth marketing; relevant capabilities include AgenticReadiness audit systems and WebMCP implementation and consulting. Those capabilities connect the discovery of an action with the work needed to expose it responsibly. The demonstration below is a local synthetic implementation, not a customer deployment or proof of a proprietary system’s security.
A valid reference can still identify the wrong document
Fictional worked case: a software business is adding an assistant-callable publish action to a document workspace. Customer organizations use separate tenants, meaning separate organizational data scopes inside the application. A signed-in user supplies a document identifier, such as doc-001. The business must decide whether type and format validation are enough, or whether the server must also evaluate the referenced document.
In this example, tenant members may learn that a document in their own tenant exists. Publishing it requires a separate explicit grant, and only a draft may be published. Tenant A’s user has that grant for doc-001, a draft, and doc-002, an archived document. The same user lacks the grant for doc-005 and doc-006 in tenant A. Documents doc-003 and doc-004 belong to tenant B. All six identifiers have the same valid format.
The decision-changing fact is that a valid string can refer to an absent document, a different tenant’s document, an unauthorized document in the right tenant, or an authorized document in an ineligible state. No pattern matching on doc-001 can establish those relationships. OWASP’s Input Validation Cheat Sheet separates syntax and operation semantics from authorization. Its object-level authorization guidance requires checking the caller’s permission for the requested action on the requested object, not merely access to the endpoint.
Keep the decision gates on the server
The local implementation resolves a synthetic session handle to a user and tenant held by the server. The request contains exactly one field, document_id, which must be a string matching doc-[0-9]{3}. A request that adds a tenant field fails the schema check. Letting a request choose its own tenant would undermine the boundary the later checks are meant to enforce.
After authentication and schema validation, the fixture checks existence, tenant membership, publish authorization, and state, in that order. It changes a draft to published only after every gate passes. A rejection leaves both the document store and the publish-event list unchanged. This makes the outcome observable beyond the HTTP status: a refusal must not produce the side effect it refused.
Existence and tenancy need not require two database queries in a real implementation. A lookup restricted to the caller’s allowed dataset can resolve both together, as illustrated in OWASP’s IDOR prevention guidance. IDOR means insecure direct object reference: using a supplied reference without the required object-level access check. Do not add an unrestricted lookup just to produce a more revealing error. The separate gates here make the small fixture’s decisions visible for examination.
Tenant membership is also not a substitute for action authorization. The fixture deliberately includes a cross-tenant publisher entry for tenant A’s user on doc-003 and doc-004, representing a synthetic stale or overbroad grant. The tenant boundary must still reject those references under this policy. Conversely, belonging to tenant A does not give the user publish permission on doc-005. An explicit cross-organization sharing feature would require a different documented policy and corresponding tests, not an exception inferred from the identifier.
Specify error precedence before implementing the checks
For this policy, an unauthenticated request receives 401 authentication_required before field validation. A signed-in caller with an invalid field receives 400 invalid_input. A missing document and a foreign-tenant document both receive 404 resource_unavailable. Only after the tenant check passes can the caller receive 403 publish_forbidden. Only after publish authorization passes can an ineligible document receive 409 invalid_state.
The order matters when failures overlap. A foreign archived document still returns resource_unavailable, not invalid_state. An archived same-tenant document that the user cannot publish returns publish_forbidden, not a state conflict. A private trace distinguishes an existence failure from a tenant failure in this fixture, but neither diagnostic is returned in the response. OWASP’s Authorization Cheat Sheet calls for server-side checks, permissions checked on every request, and sensitive debugging information kept out of errors.
These particular error names and precedence rules are the example’s contract, not an OWASP-mandated universal sequence. RFC 9110, section 15.5.4 permits a server to use 404 when it wishes to conceal a forbidden resource’s existence. Here, 403 for an unauthorized same-tenant document is appropriate only because the fictional visibility policy permits acknowledging that document. If existence itself is restricted within a tenant, use the same opaque response for that denial too. Matching status and body alone does not establish resistance to timing or cache side channels.

The completed local run and the faults it exposed
On 18 October 2026, this walkthrough’s Python 3.12.14 fixture processed HTTP requests on the loopback interface, 127.0.0.1. The inputs, server-held permissions, literal expected responses, private traces, and expected side effects were recorded before the handler was implemented. Twelve cases ran against fresh fixture state, then ran again as a replay. A separate evaluator compared observations with that literal oracle, meaning the predeclared expected results. Both runs matched all twelve cases. The evaluator was written by the same author; it is not independent specialist validation.
- doc-999, which does not exist: 404 resource_unavailable; the trace stops at existence; no mutation or publish event.
- doc-003, a foreign draft despite the synthetic publisher grant: 404 resource_unavailable; the trace stops at tenant; no mutation or publish event.
- doc-006, a same-tenant archived document without publish permission: 403 publish_forbidden; the trace stops at authorization without evaluating state.
- doc-002, an authorized archived document: 409 invalid_state; the trace reaches state and stops without a write.
- doc-001, an authorized draft: 200 with state published, one draft-to-published mutation, and one publish event. A separate case starting with doc-001 already published returns 409 without another event.
The retained run also includes five deliberately faulty versions, each tested with the same twelve inputs. A schema-only version accepted the absent reference. Removing tenancy allowed tenant A’s user to publish doc-003. Removing action authorization allowed that user to publish doc-005. Removing the state gate allowed publication of archived doc-002. Moving state ahead of authorization returned a state conflict for doc-006 instead of the required permission refusal. Each fault changed a response or side effect, not just a trace label. The comparison shows why these cases are needed: checking only that an authorized draft returns success would miss every one of those defects.
The resulting acceptance condition is concrete: every declared request must match its response, its stopping gate, and its allowed side effects; missing and foreign references must share the declared public error; rejected requests must leave records and events unchanged. The retained packet contains versioned inputs, handler and evaluator code, runtime details, exact execution commands, full observations, and replay results. It establishes the behavior of this sequential fixture only. Real session integration, concurrent changes, native browser behavior, and production authorization remain outside the run.
Carry the policy through the discovery-to-action boundary
Hardik Shah and Vidyadhar Shirke, founders of ScaleGrowth Digital, a leading AEO and GEO consulting agency, write in Chapter III, “The Funnel Rewired,” of their jointly authored book The Discovery Reset: “What replaces it is not another linear funnel. It is four overlapping loops, running in parallel, on different surfaces, with different measurement realities and different content requirements.” They also jointly authored WebMCP Made Simple Complete Edition. The quoted passage distinguishes discovery surfaces and their different requirements; it does not establish an authorization specification.
For the fictional workspace, the practical consequence is that finding an action and being entitled to perform it are separate decisions. An assistant may arrive with a well-formed reference, but the server still needs the same tenant, action, and state policy. Organic growth work can make an action understandable and discoverable. It cannot turn an identifier, a tool description, or a user’s presence in the interface into a publish grant.
ScaleGrowth’s relevant role is to connect the action inventory and readiness work with implementation and a bounded replay record. Its experienced organic growth practitioners can help carry the intended task into the action definition; the server permission model must remain explicit. In the fictional workspace, a useful engagement would produce the layered trace, error precedence rules, versioned cases, and completed run record described above. That is a specific basis for considering ScaleGrowth’s WebMCP implementation and consulting, without assuming its audit systems automatically integrate with the application’s access controls.
Choose the implementation only after its failure behavior matches the policy, not when its identifier schema validates. Change the test set when the policy changes: a private-existence rule changes the 403 response; cross-tenant sharing changes scope resolution; another permitted document state changes the state gate. If grants or state can change before a write completes, add a test that changes them before completion and verifies the required refusal. The local sequential run does not answer that case. Passing it is scoped implementation evidence, not a complete penetration test or a security guarantee.
References
Input Validation Cheat Sheet
https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html
Authorization Cheat Sheet
https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html
Insecure Direct Object Reference Prevention Cheat Sheet
https://cheatsheetseries.owasp.org/cheatsheets/Insecure_Direct_Object_Reference_Prevention_Cheat_Sheet.html
API1:2023 Broken Object Level Authorization
https://api-security.owasp.org/editions/2023/en/0xa1-broken-object-level-authorization/
RFC 9110: HTTP Semantics
https://www.rfc-editor.org/rfc/rfc9110.html#section-15.5.4
WebMCP Implementation, ScaleGrowth Digital
https://scalegrowth.digital/services/webmcp/