maniator / maniator/verticopolis

[Bug]: [P2] The web ingest route forwards platform and distribution_channel unvalidated, so desktop rows can be forged

Open
#788 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
5
Forks
1
PR merge metrics
No merged PRs in 30d

Description

Found by the Blind Hunter layer reviewing analytics stage 2 (the desktop ingest route). Not introduced by that stage; it emerges from stage 1 and stage 2 together, and neither the party ruling nor either stage anticipated it.

The hole

Stage 2 stamps platform and distribution_channel server-side on /api/ingest/desktop, after the client property spread, specifically so a crafted body cannot invent a storefront or mislabel its surface. That guarantee holds on that route.

The sibling route undoes it. /api/ingest accepts an absent Origin header (originAllowed returns true when the header is missing, by design, since non-browser clients legitimately omit it), and it forwards the client's properties untouched. So:

curl -X POST https://<host>/api/ingest   -d '{"event":"boot","session":"x","properties":{"platform":"desktop","distribution_channel":"steam"}}'

lands a fabricated Steam desktop session in the dataset. The desktop route's entire validation layer is bypassed by aiming one path to the left. Stage 2's own test documents the behavior: it asserts the web route forwards platform: "web", distribution_channel: "steam" unchanged.

Why it emerged

Stage 1 made EVERY web event carry platform and distribution_channel. Stage 2 made them server-authored on the desktop route only. Before stage 1 the web route carried no such dimensions, so there was nothing to forge; before stage 2 nothing claimed they were authoritative. The combination is what opens it.

Why it was not fixed in stage 2

Stage 2's scope constraint required the web route's behavior to be unchanged, and the fix is a real behavior change that needs a decision on shape. Stage 2 corrected its own comments, which had claimed the dimensions were server-authored without qualification.

Fix shape, and the wrinkle

The server cannot simply stamp platform on the web route the way it does on the desktop one: web versus twa is a client-side distinction (the TWA marker rides the launch URL's query string), and the server has no way to verify which one it is looking at. So the honest fix is validation rather than stamping:

  • On the web route, accept platform only from {web, twa} and rewrite anything else to unknown.
  • Accept distribution_channel only from {web, twa} and rewrite anything else to unknown, since a storefront value can only be legitimate on the desktop route.

That leaves an honest residual worth stating: a forger can still claim twa when they are web, and vice versa. Both are web surfaces, so the blast radius is one low-stakes dimension rather than a fake desktop population.

Priority

P2 rather than P3 because it is a data-integrity issue in the dataset the demo decision will be made from, and because it is cheap to fix. It is not urgent while desktop builds emit nothing (the gate is still closed), so it can land with or before the client stage, but it must land before anyone trusts a desktop count.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating the /api/ingest route and the Stage 2 test that currently asserts the web route forwards platform and distribution_channel unchanged. Trace how those properties are accepted, then validate web values against web and twa, rewriting other values to unknown, and run the relevant ingest tests to confirm desktop values cannot be forged.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend, security
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.